The workflow engine uses the ISO 8601 standard for all dates and times in process models and instances. This standard is a combined date and time format. For example, 2017-06-10T10:30:00Z, represents half past 10am on the 10th of June 2017, UTC.
The workflow engine (in fact, the whole of the API Server) works in UTC. To make this clear all time strings should include a "Z" at the end (the zone designator for the zero UTC offset).
This does mean that local times should be converted to UTC when scheduling activities to happen at specific times. You'll also need to consider the change to and from BST in the summer months.
Types of Timer
The workflow modeller includes three types of timer.
Timer start events will start an instance of the process when the defined time is reached.
Timer intermediate catching events will "pause" a workflow execution when reached and release it when the defined time is reached.
Timer boundary events are similar to catching events, but can be attached to other activities and structures in the model, rather than inline.
Timer Start, Duration and Cycle
Each of the timers have start, duration and cycle properties.
Start
Start times will fire when the defined time is reached. This can be used to start an instance at a specific time.
When used in a catching or boundary event, there is a chance that the time set may have passed before the workflow execution arrives at the timer (or the activity it is attached to). If that happens the activity will continue as if the timer wasn't there.
Start times are expressed as 2017-06-10T10:30:00Z
Duration
The duration property acts as a stop watch. The timer will start counting down from the moment the workflow process is deployed (in the case of start events) or from the time the execution arrives at the timer or attached activity.
ISO 8601 durations are prefixed with a P. Examples include:
- P1M (one month)
- PT1M (one minute)
- P1MT1M (one month and one minute)
- P1M5DT1M (one month, 5 days and one minute)
Cycle
The cycle property fires the timer on a defined cycle. In the workflow start event this can be used to start instances of the process on a repeating schedule.
Cycles are often used in boundary events when you need to set reminders. For example, attaching a timer to a user activity could trigger an email to be sent every day while the execution is waiting for the user to complete the task.
The use-case for timers in an intermediate catching event is quite small. When the execution arrives at the timer the cycle will start. When the timer fires after the first cycle the process will move on, in exactly the same way as the duration timer. Further cycles won't do anything, because the execution is no longer waiting at this timer.
ISO 8601 defines repetitions using the prefix R:
- R5/2016-06-10T10:30:00Z/P7D (repeat every seven days starting at the specified date for 5 cycles)
- R/P7D (repeat indefinitely every seven days)
- R/PT1H/2017-01-01T00:00:00Z (repeat every hour until the beginning of 2017)
While the interval syntax theoretically supports an unlimited number of repetitions, in practice it is necessary to specify a number (up to 2147483647), to avoid an issue where the timer can fail to wait for the specified interval between firings.
Timers and Suspended Instances
Should a process instance be suspended (whether using the API or controls in the modeller), any timers will not fire. However the due date of the timer is not affected by the time spent suspended.
For example, if a timer with a duration of 24 hours is activated, suspending the process for 10 hours while that timer is counting down does not extend the duration of the timer by 10 hours. The timer will still timeout 24 hours from the moment it started.
Timers that expire while a process is suspended will fire as soon as the process is reactivated.
Configuring Timers Programmatically
Timer properties can be set using expressions that reference process variables.
The start, duration and cycle properties all accept expressions using the standard ${VARIABLE} format. This means you can use a script task to modify your timers during the execution of a process instance.
Example 1 - Simple Variable Value
In this workflow, the duration of the timer is taken from a value entered on the form that started the workflow.
The form field is called DURATION, which creates a form_DURATION process variable:
Which is then used in a timer:
Example 2 - Escalating Priority
In this example a cycle is used to increase the priority of a request and send an update email. The number of repeats will vary depending on the initial priority of the enquiry, and reduce by one after each cycle. A maximum of five increases is possible, taking the request to the maximum priority.
The boundary timer has it's cycle set as ${ESCALATIONTIMERSPEC}.
The ESCALATIONTIMERSPEC is set by the "setup" script task.
// Constants
var MAX_PRIORITY = 5;
// Convert string from form data into integer process variable
var priority = parseInt(execution.getVariable("form_PRIORITY"));
execution.setVariable("PRIORITY", priority);
if (priority < 5) {
execution.setVariable("ESCALATIONTIMERSPEC", "R" + (MAX_PRIORITY - priority) + "/PT15S");
} else {
// We don't want to do it at all so set end date far in the past
execution.setVariable("ESCALATIONTIMERSPEC", "R1/PT15S/1970-01-01T00:00:00Z");
}
The second script task increases the priority by one each time, which reduces the number of possible repeats.
var priority = parseInt(execution.getVariable("PRIORITY")) + 1;
execution.setVariable("PRIORITY", priority);