Toggle menu

Messages and Signals

Messages and signals allow forms, end points, site templates and other process instances to interact with a process outside of the normal user task activities.

Messages

Messages are sent to a specific workflow process instance and can be caught by message boundary or intermediate events.

Sending Messages

To send a message to a process instance you need to know either the business key or the processInstanceId of the instance you'd like to send the message to.

All messages have a name, known as the "message reference". The message events in a process instance listen out for these references. This means you can add multiple message events to a model, each of them waiting for a different message reference.

From Forms

Messages can be sent to a process instance from a form using the Workflow - Message Action field. This field has a property where you set your message reference.

In this model, an intermediate message event pauses the workflow execution when it is reached. Its message reference is set as WaitHere.

Message Event

WaitHere

To trigger this message and resume the execution, the form field would look like this:

Message Action

Messages can only be sent like this if your form is part of the process you'd like to message, for example your form is part of a user task in the process instance you are messaging. This lets you message another part of the same workflow when the user task is completed. This works because task forms are supplied the business key of their process instance and the Message Action field automatically uses it.

From Scripted Actions

To send a message to an instance outside of normal workflow, for example from an end point, Workflow Script Task, Form Script Action, or even site templates, you'll need to use the Workflow worker's API and know either the business key or ID of the process instance to message.

The sendMessage function can use the processInstanceBusinessKey or processInstanceId to identify the instance to send the message to. See sendMessage for the latest parameter structure (you can also supply new process variables, record history and create file references).

function(params, credentials) {
    let message = this.callWorkerMethod("workflow", "sendMessage", {
        "processInstanceBusinessKey": params.businessKey,
        "messageName": "ReleaseTheHounds",
        "variables": {
            "newvariable": "newValue",
            "anotherNewOne": "another new value"
        },
        "userId": "TIMG",
        "startUserId": "ANONYMOUS",
        "historyRecording": {
            "labels": {
                "labela": "${PROCESSNAME}",
                "labelb": "${BUSINESSKEY}"
            },
            "subject": {
                "description": "${PROCESSDESCRIPTION}",
                "userId": "TIM",
                "proxyUserId": null
            },
            "event": {
                "event": "MESSAGE",
                "description": "Message Sent",
                "userRole": "user",
                "userId": "TIM",
                "proxyUserId": null,
                "private": false
            },
            "storeFormData": false,
            "formName": "TIMSFORM",
            "logSubmission": true,
            "logSummary": false
        }
    });
    return message;
}

Receiving Messages

Message events in workflow models wait for a message reference before they are triggered. Message references do not need to be unique. This means you can have several message events with the same reference in one model, all of which will be triggered when a message with that reference is received.

Intermediate Events

In this model, a user completes a task, then the execution will pause at the message event. The execution waits for a message to be received then continues to the mail task. If the message is sent to the workflow before the execution arrives at the message event, it will have no effect, and another message will need to be sent for the execution to proceed.

Intermediate Message

Boundary Messages

In this model the user task is held within a sub-process. A message boundary event is attached to the sub-process. When the message is received the sub-process will be interrupted (assuming it hasn't already completed).

Boundary Message

Whether the sub-process is cancelled or not is set in the message event. This allows you to build sub-processes that will either end when a message is received, or perhaps allow a second flow of execution to start, leaving the sub-process in place.

Boundary Message with Cancel

Signals

Signals are similar to messages with one major difference. Messages are always sent to a specific process instance. Signals can be broadcast to all workflow instances, and any signal event with a matching signal reference will be triggered. Signals can also be sent from within workflows, using the intermediate signal throwing event.

Signal Definitions

Before you can start to use signals in your workflow model, they need to be defined in the model you are working on.

Click on any blank space in the work area, then select the "Advanced" tab. You'll see the signal definition property in the left-hand column:

Advanced Tab Signal Definition

In the definition you need to set the signal name and ID (it's best if these are both the same), and its scope:

Signal Definition

Signal Scope

As mentioned above, signals can be broadcast to all workflow instances, and any that have events listening for the signal definition will respond. This means understanding signal scope is very important.

Consider this example.

Understanding Signal Scope

An instance of this workflow has two parallel paths of execution, paths A and B. When the user task in Path A completes, the execution triggers a signal throwing event, which is caught by the boundary event attached to the user task in Path B. When it is caught Path B is interrupted.

This is a perfectly valid way of doing things.

However, the signal thrown in Path A could be broadcast to all instances of this workflow, meaning that the actions in one instance will interrupt every other active instance!

There may well be cases when you want this to happen. For example, your workflow may relate to a delivery service, and should the delivery truck break down, you need to notify every instance/delivery that is currently active.

On the other hand, if all you want to do is to throw a signal that will be caught by the boundary event in this instance without affecting any other instances, you need to change the scope of your signal definition.

Signal Scope

The default value is Global. Changing the scope to Process Instance means that the thrown signal will be contained within this instance and that any events that are listening for this signal will only respond if it is thrown from within the same instance.

Sending Signals

As in the example above, signals can be sent using the intermediate signal throwing event in the workflow modeller.

You can also send signals from forms, end points and site code using signalEvent in the Workflow worker's API.

This example sends a signal from an end point. The signal it throws has been defined (in the workflow modeller) as having Global scope, so all instances will respond.

function(params, credentials) {
    let signal = this.callWorkerMethod("workflow", "signalEvent", {
        "signalName":"MyGlobalSignal",
        "userId":"tim"
    });
    return signal;
}

Should the signal definition have a Process Instance scope, you cannot send signals to it using the API. The event listeners within the instances will only ever respond to signals sent from within the same instance.

You can target a specific instance by providing the execution ID. Execution IDs can be tricky.

As a process instance executions progress, they generate a series of child executions as each task in the instance is reached, each of which has a unique ID. These executions are represented by an array of objects.

For example, this model generates four executions.

Signals and Executions

Once an instance starts, it's possible to see the following, by calling the Workflow worker's getExecutions and providing the process instance ID:

{
    "jsonrpc": "2.0",
    "id": 875,
    "result": {
        "id": "_272",
        "result": {
            "result": {
                "count": 4,
                "list": [{
                    "id": "38177",
                    "activityId": "Signal",
                    "parentId": "38175",
                    "isEnded": false,
                    "processInstanceId": "38158",
                    "isSuspended": false,
                    "activeActivityIds": ["Signal"]
                }, {
                    "id": "38176",
                    "activityId": "UserTask1",
                    "parentId": "38158",
                    "isEnded": false,
                    "processInstanceId": "38158",
                    "isSuspended": false,
                    "activeActivityIds": ["UserTask1"]
                }, {
                    "id": "38175",
                    "activityId": null,
                    "parentId": "38158",
                    "isEnded": false,
                    "processInstanceId": "38158",
                    "isSuspended": false,
                    "activeActivityIds": ["Signal"]
                }, {
                    "id": "38158",
                    "activityId": "Gateway",
                    "parentId": null,
                    "isEnded": false,
                    "processInstanceId": "38158",
                    "isSuspended": false,
                    "activeActivityIds": ["Signal", "UserTask1"]
                }]
            }
        },
        "jsonrpc": "2.0"
    }
}

To send a signal to this instance, you need to target ID 38177, the execution that corresponds to the "Signal" activityId (it's for this reason it's good practice to assign IDs to your activities, rather than the random number generated by the workflow engine).

Here's how we can signal the instance from an end point.

function( params, credentials ) {
    let signal = this.callWorkerMethod("workflow", "signalEvent", {
        "signalName":"MyGlobalSignal",
        "executionId":"38177",
        "userId":"tim"
    });
    return signal;
}

Receiving Signals

There are two workflow events you can use to receive signals, one intermediate event that will pause an execution when reached, releasing it when a signal is received, and a boundary event that can be attached to tasks and sub-processes, interrupting them when the signal is received. These work in the same way as the message events described above.

Last modified on January 23, 2024

Share this page

Facebook icon Twitter icon email icon

Print

print icon