FIM 2010: Event Driven Run Profile Scheduling using a Windows Service
Source reference
Originally posted at: FIM 2010: Event driven scheduling @ IS4U Blog
Introduction
This companion Wiki article describes how to implement a windows service for scheduling Forefront Identity Manager.
In case you need to trigger the synchronization "on demand". A specific trigger for a synchronization cycle, for example, can be the creation of a user in the FIM portal.
Trigger
Core question: "Is it possible to send a signal to our existing Windows service to start a synchronization cycle?". All the functionality for scheduling is already there, so it seems reasonable to investigate and explore this option. As it turns out, it is possible to send a signal to a Windows service and the implementation turned out to be very simple (and simple is good, right?).
In addition to the scheduling of predefined moments defined in the job configuration file, which is implemented through the Quartz framework, you should use an extra thread:
while ( true )
{
if (scheduler.GetCurrentlyExecutingJobs().Count == 0 && !paused)
{
scheduler.PauseAll();
if (DateTime.Compare(StartSignal, LastEndTime) > 0)
{
running = true ;
StartSignal = DateTime.Now;
LastEndTime = StartSignal;
SchedulerConfig schedulerConfig = new SchedulerConfig(runConfigurationFile);
if (schedulerConfig != null )
{
schedulerConfig.RunOnDemand();
}
else
{
logger.Error( "Scheduler configuration not found." );
throw new JobExecutionException( "Scheduler configuration not found." );
}
running = false ;
}
scheduler.ResumeAll();
}
// 5 second delay
Thread.Sleep(5000);
} |
StartSignal
The first thing it does is check if one of the time-triggered schedules is not running and the service is not paused. Then it checks to see if an on-demand trigger was received by checking the StartSignal timestamp. So as you can see, the StartSignal timestamp is the one controlling the action. If the service receives a signal to start a synchronization schedule, it simply sets the StartSignal parameter:
|
The first thing it does next if a signal was received, pauses the time-triggered mechanism. If the synchronization cycle finishes the time-triggered scheduling is resumed. The beautiful thing about this way of working is that the two separate mechanisms work alongside each other. The time-triggered schedule is not fired if an on-demand schedule is running and vice versa. If a signal was sent during a period of time the service was paused, the on-demand schedule will fire as soon as the service is resumed. The StartSignal timestamp will take care of that.
StartSync
So, how do you send a signal to this service, you ask? This is also fairly straightforward. I implemented the FIM portal scenario I described above by implementing a custom C# workflow with a single code activity:
|
You can find more info about Windows services and custom commands here and here.
If you want to know more about developing custom activities, this article is a good starting point.
The integer value is arbitrary (although it has to be in the range 128-255). You only need to make sure you send the same value as is defined in the service source code. The ServiceController takes the system name of the Windows service.
PowerShell
The same is possible in PowerShell:
|
Another extension implemented (inspired by Dave Nesbitt's question on this companion Wiki article) was the delay step. This kind of step allows you to insert a window of time between two management agent runs. This in addition to the default delay, which is inserted between every step. So now there is four kind of steps possible in the run configuration file: LinearSequence, ParallelSequence, ManagementAgent and Delay. Saw the same idea being implemented in PowerShell here.
A very useful function I didn't mention in my previous post but was already there, is the cleanup of the run history (which can become very big in a fast-synchronizing FIM deployment). This function can be enabled by setting the option "ClearRunHistory" to true and setting the number of days in the "KeepHistory" option. If you enable this option, you need to make sure the service account running the service is a member of the FIM Sync Admins security group. If you do not use this option, membership of the FIM Sync Operators group is sufficient.
The source code and the installer for the windows service described in this article can be found on GitHub.
Configuration
Also implemented a GUI to ease the process of configuring the scheduler. More information can be found at following blog article: GUI for configuring your scheduler.
References
- ServiceBase.OnCustomCommand Method: http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.oncustomcommand.aspx
- ServiceController.ExecuteCommand Method: http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.executecommand.aspx
- Custom Activities and Workflows: http://msdn.microsoft.com/en-us/library/windows/desktop/ee652258(v=vs.100).aspx
- Schedule FIM 2010 with a sleep option: https://konab.com/schedule-fim-2010-sleep-option/
See also
Some other pointers to other existing schedulers for FIM at
- FIM 2010: How to Automate Sync Engine Run Profile Execution
- FIM 2010: How to use Windows Service for Scheduling Run profiles