piątek, 23 stycznia 2015

MultiInstance Characteristic example - Reward Process

One of a great features of BPMN (and not only) is the multi instance activity aka for each. To put it simple same activity is repeated for each item from input collection. That is usually good fit for distributing work across number of people to gather their input or opinion.
jBPM provides support for it since version 5 but it was enhanced with every version. Current support covers:

  • subprocess and individual task
  • input and output as collection
  • completion condition on entire multi instance activity (subprocess or task)

Equipped with that we can build powerful processes with simplified structure. Even more than that: it's all dynamic meaning number of instances can (and actually should as best practice) reference process variables for both input and output.

To show it in practice we go over an example that is based on Eric Shabell's Reward demo. It has been only slightly modified to focus mainly on the multi instance support jBPM comes with in version 6.2 community. 

So what we have in this process?
  1. When process start it will ask for some details about the person who shall receive award and its details
  2. Once instance is started it will go into 'Associate Reviews' user task where associate needs to provide following information:
    1. how many peer reviews should be performed
    2. how many of them are required to move on without waiting for all to be completed
  3. Once this information is available 'Setup Reviews' task will prepare all required structures and populate process variables that will feed multi instance subprocess
  4. 'Evaluate Award' task will be created multiple times based on (2.1) selection
  5. Each instance of that user task will ask for approval and result of it will be kept in multi instance output collection
  6. It has a completion condition that will evaluate result every time one instance of 'Evaluate Award' task is completed as soon as it becomes true it will move on and cancel remaining task instances of 'Evaluate Award'
  7. 'Calculate results' will be performed to check what output is collected - if award is approved or rejected and based on that will go to one of the paths.
So let's review process configuration in details, starting with process variables

This in general is nothing special, just worth noting two variables:
  • reviews_collection
  • reviews_results
both are of type java.util.ArrayList (they can be of any collection type) and they will be used for configuring multi instance subprocess. Important to note is that both must be non null before they can be used in multi instance activity.

Next let's review how the multi instance activity is configured:

MI collection input - this is the collection which will be used to create individual instances of given activity. In other words, each element from that collection will be assigned to separate activity instance.
MI collection output - this is the collection which will collect results of execution of multi instance activity - will aggregate all results produced. This is optional as not every multi instance activity must produce result that shall be collected.
MI completion condition - expression (currently MVEL) that will be evaluated at every completion of activity instance and as soon as it becomes true it will leave multi instance activity even if not all instances are completed. Those not completed will be canceled.
MI data input - this is the variable name that will be given to individual activity instances produced by multi instance activity. 
MI data output - this is the variable name where the output of individual activity instance will be stored. It's optional as not all activities must produce results

Last but not least let's take a look in details at the completion condition as it provide quite powerful way of controlling multi instance activity completion.

In case it won't be readable (or for copy paste reason) here is the expression:

($ in reviews_results if $ == true).size() == approvalsRequired;

so what does it say? In general it evaluates all items in the 'reviews_results' collection and counts all elements that has value set to 'true'. Next it compares its size with the 'approvalsRequired' process variable to check if already collected approvals is enough.

For those interested, this is MVEL projections example which gives very powerful option to operate on collections.

That would be all to this article. For complete runnable example visit github. You can directly clone it from your kie-workbench installation (aka jbpm console) and run it there. It comes with all required parts:
  • process
  • forms
  • data model
All configured and ready to be executed (just make sure you run on jBPM 6.2 or higher). Enjoy

As usual comments and feedback most welcome.

17 komentarzy:

  1. hello, thank you for this good example. One question: I added a Timer to 'Evaluate Award' to cancel the task after some time without user interaction. If I create a process instance with - for example -three
    Multiple Subprocess 'Evaluate Award' - tasks only two of them are cancelled. One keeps alive. I would expect, that all three tasks are be cancelled and the main process starts
    the Calculate results task. What I'm doing wrong? thanks in advance.

  2. it should cancel all instances as long as they all have timer created which of course it should in this case. Alternatively you could attach timer not to the subprocess instance so it will cancel all of them at once.

    What I suspect is that there is a bit of race condition going on as all timers fire at the same time and might fail to update same process instance. If you change their timer expiration time to differ a bit - so they won't fire at the same time might tell if that's the issue.

  3. I tried it with different timers (PT6s, PT8s, PT11s) , but still one Task remains uncancelled.?
    Another question: How can I accomplish the following: if one of the tasks is cancelled by timer, all other multiple instance tasks should be cancelled automatically, or even the whole (parent) process should be cancelled? thanks in advance.

  4. use signal boundary event (with cancel activity set to true) attached to subprocess that will do the cancel of required activities within the subprocess. Then you can send the signal after timer fired.

  5. Thank you very much, now the process does what I want.

  6. I have another question: is it possible to use a Multiinstance Subprocess within a Multiinstance Subprocess? I have to send one or more emails depending of data of the enclosing Multiinstance Subprocess. I define a collection variable in the enclosing Multi Inst. Subprocess, but can't set this variable as Collection Input of the inner Multi Inst. Subprocess. In the Listbox of the designer are only variables of the main process. I'm using jBPM console 6.5 CR2. Thanks in advance.

    1. it looks like limitation in the designer so you might try to workaround by specifying process variable so you can select it. Feel free to file jira issue as well.

  7. Hi Maciej,
    I get an error when I try to run this project in Kie Workbench 6.4.0.Final

    "Unexpected error occurred: java.lang.IllegalArgumentException:Unexpected collection type: class java.lang.Integer"

    I attach the image with error https://i.imgsafe.org/892c8ed40d.png

    Thanks in advance

    1. looks like you're trying to set integer as input to multi instance which expects (and supports only) collections. So if you have this multi level setup you need to have collection with collections as it's items so then there will be each level represented as collection.

  8. Hi Maciej,

    Is it possible to add a new instance to the Multiple instance subprocess on runtime?

    For example in your process, if we have 2 instance of Evaluate Award SubProcess,
    while waiting for those 2 instance to finish, can we add another instance of Evaluate Award Subprocess?

    If it is possible, then will the MultipleInstance SubProcess node wait for all 3 instance to finish before proceeding to "Calculate Results" node?

    Thank you

    1. nope, unfortunately it's not possible to add node to active multi instance

  9. Hello Maciej,
    i am working with "Multi-instance sub-process" and with his "variable definition", so i created some vars and when i try to used them in the "Gateways" i cant find my variables, what should i do ?

  10. Hello Maciej,

    I am working in a similar process, and I need to use the MI data input (EMPLOYEE) for getting the ID using the method employee.getID(). But I can't do it because I got the error "The method getId() is undefined for the type Object". What should I do?

    1. double check your process variables if they have proper type as it seems it can't resolve to expected type and thus fallbacks to considering as Object.

    2. I have checked, and the variable have the proper type.

  11. Ten komentarz został usunięty przez autora.