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:

 

protected  override void OnCustomCommand(int command)
{
 if  (command == ONDEMAND)
 {
  StartSignal = DateTime.Now;
 }
}

 

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:

using System.ServiceProcess;
 
private  const int OnDemand = 234;
 
private  void startSync(){
 ServiceController FIMScheduler = new ServiceController("FIMScheduler");
 FIMScheduler.ExecuteCommand(OnDemand);
}

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:

[System.Reflection.Assembly]::Load("System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$FIMScheduler = New-Object System.ServiceProcess.ServiceController
$FIMScheduler.Name = "FIMScheduler"
$FIMScheduler.ExecuteCommand(234)

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

 


See also

Some other pointers to other existing schedulers for FIM at