User tasks are normally completed by a single user. But what if you need the same task to be completed by multiple users, and your workflow only continues once everyone has completed it? This article looks at how you can use call activities to create new instances assigned to users. You'll find a working example in the downloads area.
Multi-Instance Tasks
The article on Multi-Instance Tasks looked at the basic steps needed to set up a task that repeats multiple times, and discussed some of the problems in making a user activity multi-instance. The most frustrating of these is that, because form fields and their values are stored as process variables, once one user has completed the form, subsequent users can't complete the same form without seeing or overwriting what the previous user submitted.
To make sure each user task is entirely independent, use a call activity to create a new process instance for each user.
Call Activities
Call activities are used to start an instance of another process. You have complete control over the process variables passed into the new instance, and can set which variables are returned to the parent instance when the target instance completes.
Call activities can also be set as multi-instance. This means multiple new workflow instances can be created and the parent workflow won't continue until they have completed.
Example
This example imagines a new policy being implemented in a workplace. Every member of staff must confirm they have read the policy. A multi-instance call activity is used to create a workflow instance for every user in the staff group. The new instances have a form the user must complete. Once all staff members have completed their tasks, an email is sent to the user who started the parent process.
Parent Process
The parent process sets up the call activity.
Get The Users
The first activity calls an End Point to fetch the names of all of the users in our staff group. Exactly how it does that is beyond the scope of this article (an End Point is included in the example download). The important thing for this workflow is that users are returned and stored as an array in a return variable called USERS.
Inspecting an active instance of this process, you'd see the users like this:
Creating the Instances
The advanced tab of the call activity controls the multi-instance settings.
Instances are created in parallel, going to all users at the same time.
The "Collection" property looks for the USERS process variable (created by the End Point activity), and will create an execution for every item in that array.
The "Element variable" property creates a process variable called "user" for each new execution. The value of this new variable is the value of the item in the collection the execution has been created for, ie each new execution will have a process variable called user that holds a single username.
The main tab of the call activity sets up the new instances for each execution.
The "Process ID" property is the process the activity will start instances of. It will always start the "latest" version. You can pass process variables from the parent process to each new instance using the "In parameters". In this case each instance will be given the "user" variable created for each execution, plus the history labels of the parent process (see below).
Target Process
Once started the target process operates independently of the parent, it can be as simple or complex as you need. In this example there's a single user task and a task to record history.
User Task
The user task will be assigned to the user this instance was created for, passed in as a process variable by the call activity's in-parameters.
History Task
Unlike process instances started by form submissions, instances started by call activities don't automatically record history.
You could record the result of the user task using fields in the task form (either the history write field or the database save field would work). This example uses a history task in the model, with the labela and labelb values of the parent process and additional values for labelc and labeld.
Including additional labels means a new history is written for each instance. This works because we know each username will be unique.
If the task only used the labela and labelb values of the parent instance's history, it would write to that history, then seal/close it when this instance ends. You could, of course, not use those labela or labelb values and create a completely new history with no link at all to the parent.
The Result
Putting everything together we get:
- A parent process that pauses when it reaches the call activity
- A new instance created for every user in the array returned from the End Point
- A user task assigned to each user
- A history record for the parent process
- A history record for each child process
- An email sent when all of the child instances have completed