Skip to main content

Timers

Overview

A Timer represents one of internal triggers that makes a process leave the idle state and perform a specific action. Timers can be exceptionally useful to schedule a certain action or event within your project. For example, you can create a timer that will send an email after your specified time interval.

The primary advantage of timers is their ability to automate processes, eliminating the need for manual intervention in routine tasks. Therefore, timers enable the execution of actions at precise moments, which in turn allows enhancing accuracy. Timers can also optimize resource allocation by automating tasks, contributing to overall operational efficiency.

In addition, timers can be aligned with working hours and days, ensuring actions are performed only within specified operational periods. The system also allows establishing and configuring your work calendars. Learn more about setting up timers with work calendars in the Work Calendars article.

The system incorporates specific properties and rules that ensure the correct and optimized execution of your specified actions and events. The following introduces such properties, rules, and provides other important technical specifications of the Timer functionality.

Timer Properties

The system allows configuring various properties of your timer by using a corresponding button on the Toolbar. Once this button is clicked, the following properties become available for the subsequent modification:

  • Name: All timer objects are identified by their case-sensitive names.
  • Type: Your selected timer type influences the Timer Value interpretation.
  • Value: Depending on your specified Type, the system allows setting one of the following values:
    • Interval: If you select this type, you can establish a delay for a subsequent action and utilize the following units:
      • An integer, interpreted as milliseconds (e.g., 1);
      • An integer followed by 'd'/ 'day'/ 'days', indicating days (e.g., 2d);
      • An integer followed by 'h'/ 'hour'/ 'hours', indicating hours (e.g., 3h);
      • An integer followed by 'm'/ 'minute'/' minutes', indicating minutes (e.g., 4m);
      • An integer followed by 's'/ 'second'/ 'seconds', indicating seconds (e.g., 5s);
      • An integer followed by 'ms'/ 'millisecond'/ 'milliseconds', indicating milliseconds (e.g., 1ms);
      • Note that the interval measurement units can be combined, for example, "2d 5h 24m 15s", "2days 5hours", etc.
    • Date: In case this type is selected, the system will trigger an action on a specified date at 0 hours 0 minutes. The date format is MM/dd/yyyy by default, for example, 02/20/2020.
    • Time: Selecting this type will activate an action at a designated time. If the specified time has not yet occurred when the timer is set, it will trigger on the current day; if the time has already passed, it will activate on the following day. The default time format is in 24-hour HH:mm:ss, for example, 15:45:55.
    • Date And Time: This type triggers an event 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;
  • Override: If set to true (i.e., checked), your provided Timer Value cannot be overridden in case a timer object with the same name is already exist in the WorkflowProcessTimer table. This feature can be helpful to implement complex use case scenarios. For example, you can orchestrate the system to trigger a service call every 5 minutes within a 2-hour window and structure this operation as a singular activity.
Important to note

In case of using the <w> notation before provided Interval timer values (e.g., 1wd for 1 workday), the system will activate the timer according to your provided work calendar. Refer to the Work Calendars article for more details.

Exception Handling

caution

The Timer Manager, integrated within the Workflow Engine library, operates independently in a distinct thread from the ThreadPool. However, a scenario where an unhandled exception arises within your process instance triggered by the timer could result in two significant issues:

  • The critical details pertaining to the exception could potentially be lost.
  • The standard behavior of the .NET framework might lead to the termination of your application process.

In order to avoid any issues with exceptions, it is always required to create the OnWorkflowError event handler as follows:

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;
}
};

Therefore, the provided event handler will be included into the Workflow Server.

IIS warning

caution

In case you host WorkflowRuntime via an IIS server (or any other web server) and want to utilize timers, it is necessary to keep your server up so that it will not stop running a process when there are no active queries. Thus, for example, the required setting within IIS is called Idle Time-out and it is applied to Application Pool.

Timer Execution Rules

In order to successfully deploy timers within WorkflowRuntime, follow the steps bellow:

  1. 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();
  1. Call Start() method to launch the workflow runtime:

    runtime.Start();

As a result, the timers should be deployed within the workflow runtime.

The WorkflowRuntime object incorporates TimerManager. As the name suggests, the TimerManager is used to control the execution of timers within the system. These timers, associated with specific tasks, are stored in the WorkflowProcessTimer table. When an internal timer triggers, the TimerManager identifies the timers set for execution at the current time and schedules their tasks accordingly. Note that timer execution closely resembles command execution, with the key distinction being that it's initiated by the TimerManager. The process does not receive any parameters apart from the name of the triggered timer.

Upon task scheduling, the TimerManager calculates the next triggering time and updates the internal timer accordingly. If the server has experienced a prolonged idle state during which timers were meant to execute, they will be executed immediately once the runtime.Start() command is invoked.

In case a process reaches a new Activity that contains a Transition triggered by Timer, the system initiates the following sequence of actions:

  • All timers associated with the process that do not trigger any transitions from the new Activity are removed.
  • Timers responsible for triggering transitions from the new Activity are determined. Each timer is assigned a specific triggering time.
  • The triggering configurations for each timer are recorded in the WorkflowProcessTimer table. In case a timer with the same name already exists, the system checks the Override attribute. If this attribute is set to false, the timer's triggering time will not be updated.

When the designated triggering time of the Timer is reached, the system selects all associated transitions from the current Activity within the corresponding process. Note that the system also identifies the right transition that should be executed. Thus, for instance, in case multiple conditions are established for transitions, the system checks these transitions and selects a required transition that should be executed.

Implicit Timers and Manual Timer Adjustment

The timing of Timer execution might remain during your process creation, and/or it can be determined by the underlying business logic. In such cases, two specific Values can be assigned to Timers, regardless of the selected Timer Type.

  • 0: If the Timer Value is not assigned, the transition behaves like one with an Auto trigger, leading to immediate execution.
  • -1 - If the Timer Value is not assigned, the transition will never be executed.

Once the process reaches the associated Activity, and the transition's Timer Value in the scheme is assigned to 0 or -1, the system checks whether the Timer Value has been allocated for the process (this information is stored in process Parameters). If the Timer Value remains unset, the system activates an event, prompting the following handler to determine the trigger time:

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

In case triggering time is not specified, the aforementioned rules of interpreting Values 0 and -1 will be applied. If a specific value is provided, it is saved within the process Parameters, effectively configuring the Timer to activate at the designated time.

The WorkflowRuntime object offers two methods for modifying the timing of Timer triggers.

To establish a new Timer Value, utilize the following method:

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

The following method is used to set a new Timer Value within the process (i.e., in the Actions code):

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

To reset your timer according to the specified Value in the schema, it is required to use the following method:

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

Timer can also be reset to the specified Value in the schema directly from within the process (i.e., in the Actions code)

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

When setting and resetting your timers, you should consider the fact that if a timer has already been triggered in the system, and it is not been protected from changes by setting the Override attribute to false, this value will be changed immediately. For example, the following code will lead to the immediate execution of the transition triggered via TimerName:

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