Skip to main content

Timers

General information

Timer is one of the internal triggers that make a process leave the idle state and perform a certain action. Timer is an internal trigger.

The description of Timer is provided in the Timers section, which may be accessed by clicking on a corresponding button in the toolbar. The following Timer properties are available for modification:

  • Name is a Timer name. All Timers are identified by the case-sensitive name;
  • Type is a Timer type that influences the Timer Value interpretation;
  • Value is a Timer value. Depending on Type, you may set the following Values:
    • Type = Interval. This is an interval Timer; its triggering time is determined by Time of timer setting + Interval. If a set interval represents an:
      • integer, its value is interpreted as milliseconds;
      • integer followed by d, day or days, its value is interpreted as days (24 hours);
      • integer followed by h, hour or hours, its value is interpreted as hours;
      • integer followed by m, minute or minutes, its value is interpreted as minutes;
      • integer followed by s, second or seconds, its value is interpreted as seconds;
      • integer followed by ms, millisecond or milliseconds, its value is interpreted as milliseconds;
        The interval measurement units may be combined, for example, "2d 5h 24m 15s", "2days 5hours", etc.
    • Date - Timer will trigger at a specified date at 0 hours 0 minutes. The date format is MM/dd/yyyy by default, for example, 02/20/2020;
    • Time - Timer will trigger at a specified time; if upon setting of Timer the specified time has not yet come, Timer will trigger today; if it has, it will trigger tomorrow. The date format is a 24-hour HH:mm:ss by default, for example, 15:45:55;
    • DateAndTime - Timer will trigger at a specified time and date. The date format is MM/dd/yyyy HH:mm:ss by default, for example, 02/20/2020 15:45:55;
  • Do not override timer if exists - the set Timer Value will not be overridden, if Timer with such name already exists in the WorkflowProcessTimer table (object).

Exception handling

caution

Timer manager, which is included into the Workflow Engine library, executes all timers in a separate thread from ThreadPool. If an unhandled exception takes place in your process instance which will be triggered by the timer, it will lead to the following two mishaps:

  • all information about the exception might be lost.
  • your application process might be terminated, because this is standard behavior of the .NET.

To avoid this, always create the OnWorkflowError event handler:

WorkflowRuntime.OnWorkflowError += (sender, args) =>
{
var isTimerTriggeredTransitionChain =
// for timers executed from main branch
!string.IsNullOrEmpty(args.ProcessInstance.ExecutedTimer)
// for timers executed from subprocess
|| (args.ProcessInstance.MergedSubprocessParameters != null
&& !string.IsNullOrEmpty(args.ProcessInstance.MergedSubprocessParameters
.GetParameter(DefaultDefinitions.ParameterExecutedTimer.Name)?.Value?.ToString()));

if (isTimerTriggeredTransitionChain)
{
YourCustomLogExceptionFunction(args.Exception);
args.SuppressThrow = true;
}
};

Such an event handler is included into the Workflow Server.

IIS warning

caution

If you host WorkflowRuntime under IIS (or another web server) and want to use timers, you need to set your server up in such a way so that it does not stop a running process when there are no queries. For example, in IIS these settings are called Idle Time-out and are applied to Application Pool.

Rules of Timer execution

In order for timers to work in WorkflowRuntime, you need to perform the following actions:

  • configure the WorkflowRuntime for single-server or multi-server environment:

    • Use the following call for the single-server environment:

      runtime.AsSingleServer();
    • Use the following call for the multi-server environment:

      runtime.AsMultiServer();
  • call Start() method of the workflow runtime:

    runtime.Start();

    After that timers will be executed.

Inside the WorkflowRuntime contains a TimerManager (implements TimerManager interface) that controls the execution of timers. The array of Timers that should be executed is written to the WorkflowProcessTimer table (object). When the internal Timer is triggered, TimerManager selects Timers that should be executed by the current time from the array of Timers, and sets the tasks for their execution. Timer execution is very similar to Command execution; the only difference is that it is initiated from TimerManager, and no parameters are conveyed to the process, except for the name of the triggered Timer. After the tasks are set, TimerManager determines the next triggering time and sets the internal timer at it. If the server has been in an idle state for a long time, and there were Timers that should have been executed during the idle period, they will be executed immediately after runtime.Start() is called.

When a process reaches a new Activity which has a transition triggered by Timer, the following actions take place:

  • All Timers that exist for this process and do not trigger any transition from the new Activity, are removed;
  • Timers that trigger the transitions from the new Activity are determined; each Timer is set at a certain triggering time;
  • Each Timer's triggering time is written to the WorkflowProcessTimer table (object). If Timer with such name already exists, attribute Do not override timer if exists is analyzed; if it is true, the Timer's triggering time is not updated;

When the Timer's triggering time comes, all transitions from the current Activity of the process, triggered by this Timer, are selected, and the transition that should be executed is identified. For example, if there are conditions set for transitions, they will be checked, and, as a result, a single transition will be selected for execution.

Implicit Timers and manual adjustment of Timers

The time of Timer execution may be unknown at the moment of process creation, and/or be determined by the business logic. Two special Values may be attributed to Timers; the Timer type does not matter in this case.

  • 0 - if Timer Value has not been set, the transition equals to a transition with an Auto trigger, meaning that it will be executed immediately;
  • -1 - if Timer Value has not been set, the transition will never be executed.

When a process reaches an Activity, the transition from which is triggered by Timer, and Timer Value in the scheme equals 0 or -1, the system checks whether Timer Value for the process has been set (it is saved in process Parameters). If Timer Value has not been set, the system calls the event whose handler can specify the triggering time:

runtime.NeedTimerValue += delegate(object sender, NeedTimerValueEventArgs args)
{
foreach (var timerValueRequest in args.TimerValueRequests)
{
timerValueRequest.NewValue = DateTime.Now.AddDays(1);
}
};

If the triggering time has not been specified, the aforementioned rules of interpreting Values 0 and -1 are applied. If the value has been set, it is saved in the process Parameters, and Timer is set at a specified time.

Object WorkflowRuntime has two methods that allow to adjust the time of Timer triggering.

You can use the following method to set a new Timer Value:

var newValue = DateTime.Now.AddDays(1);
WorkflowInit.Runtime.SetTimerValue(processId, "TimerName", newValue);

You can use the following method to set a new Timer Value from the inside of the process (in other words, from the Actions code):

var newValue = DateTime.Now.AddDays(1);
WorkflowInit.Runtime.SetTimerValue(processInstance, "TimerName", newValue);

You can use the following method to reset Timer at the Value specified in the scheme:

WorkflowInit.Runtime.ResetTimerValue(processId, "TimerName");

You can use the following method to reset Timer at the Value specified in the scheme from the inside of the process (in other words, from the Actions code):

WorkflowInit.Runtime.ResetTimerValue(processInstance, "TimerName");

When setting and resetting a Timer, you should consider the fact that if the Timer has already been triggered in the system, and it has not been protected from changes by the Do not override timer if exists = true attribute, it's value will be changed immediately. For example, the following code will lead to the immediate execution of the transition triggered by Timer "TimerName":

var newValue = DateTime.Now.AddDays(-1);
WorkflowInit.Runtime.SetTimerValue(processInstance, "TimerName", newValue);