cancel
Showing results for 
Search instead for 
Did you mean: 

Looping Activiti Workflow

coner
Champ in-the-making
Champ in-the-making
I have been trying to implement a daemon process that will wakeup and do some work every X time in activiti.

I was able to do this with 2 service tasks and an exclusive gate that loops back to the first task, but after the flow executes 92 times it crashes, always.

It reports back a stackOverflow error and dumps an enormous number of lines.  How are serviceTask execute methods being called throughout a workflow?  It appears that they are called recursively and not sequentially regardless of the workflow layout. 

there are no variables within the execute() function that are created via "new" inside of that method.

start -> print "hello" -> sleep() -> exclusiveGate -> exit
                  ^————————|
38 REPLIES 38

coner
Champ in-the-making
Champ in-the-making
if the memory is written out in the wait states, why can't it just be written out after every step in the workflow? or via some java service task call on demand? the functionality exists, it just isn't accessible via service tasks.


the user guide calls it a "Java Receive Task"
http://www.activiti.org/userguide/index.html#bpmnReceiveTask

again:

ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
Execution execution = runtimeService.createExecutionQuery()
  .processInstanceId(pi.getId())
  .activityId("wait")
  .singleResult();
assertNotNull(execution);
   
runtimeService.signal(execution.getId());

this would be code that is executed in a java service task that would result in the receiveTask process being executed/started, and then passing a signal to that specific execution of the receiveTask process to leave the waitstate, correct?

could you elaborate on:
This could e.g. be done by a minimal service task that puts a message in a jms queue somewhere, followed by a receive task (wait state! so persistence takes place, so memory is freed) with a timeout on it that makes it continue/loop… After the job finishes normally, the receive task is triggerd.
i am confused as to the actual layout of this.
start -> JMS to somebody that does work? (a workflow?) -> recv task -> timeout -> go back to START or END?

by "simple tasks" i meant simple "workflows"

i said "hence"… because i just spent a whole paragraph explaining (overview) of what i am actually doing, as an explanation for why my approach stated in the past few messages is slightly complicated.

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
if the memory is written out in the wait states, why can't it just be written out after every step in the workflow?
That is what Async continuations is about

? or via some java service task call on demand? the functionality exists, it just isn't accessible via service tasks.
No, it's not that simple, not if you also want the flow to continue… (it's not extremely complicated either, but needs work)

the user guide calls it a "Java Receive Task"
http://www.activiti.org/userguide/index … eceiveTask
Sorry, my bad… apologies. The reason they call it this way is that there is e.g. no 'jms-receive-task', or 'web-service-receive-task', you can only use the java api. (bpmn has no notion of different reveive tasks, there it is a generic receive task)

this would be code that is executed in a java service task that would result in the receiveTask process being executed/started, and then passing a signal to that specific execution of the receiveTask process to leave the waitstate, correct?
No, not fully. The starting of the process is done separately (can be confusing to some extend that this is mentioned here)

Execution execution = runtimeService.createExecutionQuery().processInstanceId(piId).activityId(activityId).singleResult();
runtimeService.signal(execution.getId());
would be in the external code ('callback') e.g. an mdb that receives a message that contains the process instance id (piId) and activity id (activityId) which I turned into variables

could you elaborate on:
Sure
This could e.g. be done by a minimal service task that puts a message in a jms queue somewhere, followed by a receive task (wait state! so persistence takes place, so memory is freed) with a timeout on it that makes it continue/loop… After the job finishes normally, the receive task is triggerd.
i am confused as to the actual layout of this.
start -> JMS to somebody that does work? (a workflow?) -> recv task -> timeout -> go back to START or END?
"jms to somebody that does work" can be to a workflow, but it can also be to a 'simple' service (sleep() 😉 What it is does not matter. It is asyc and fully loosely coupled (I hate that term).But you HAVE TO put at least the process instance id and activity id in there so that they can be used in the callback (the combination being the 'correlation'. After that the recv task is a wait-state, so all the commits are done and memory is 'freed'. Then you either receive a message and continue that flow how it is configured or a timeout occurs and the flow does takes a different path. If in this latter case you set 'cancelActivity' to true, the recv task wil disappear. So you have to take this into account in the code above that it might be that you do not find an execution if after a delay you do receive the message. So you get something like


Execution execution = runtimeService.createExecutionQuery().processInstanceId(piId).activityId(activityId).singleResult();
if (execution != null) {
   runtimeService.signal(execution.getId());
} else {
   // silently ignore this, or log something since either there was no execution in this state because it moved on, or a wrong combination of piId and activityId were passed on
}
If you put this in an mdb, or in a simple java class that gets WS or Rest annotations or even a simple file poller, you 'effectively'  created the 'corresponding' receive tasks.

The 'funny' thing is that with some custom send/receive tasks, the line between an ESB (with 'flow/orchestration) and a BPMS becomes blurry.If you read
http://blogs.mulesoft.org/integrating-activiti-bpm-with-jms/ you see that you can use Mule, but you could also create some simple jms mdb's that interact with activity. Personally I opt more and more for the latter (or using Camunda PSI), instead of learning the config things of Mule. Mule does have nice things, so do not get me wrong, it is a good product, but even they themselves start discussing these things http://blogs.mulesoft.org/to-esb-or-not-to-esb/

Good night (it's 02:46 local time, worked over 1 hour on this post, so hope it helps)

coner
Champ in-the-making
Champ in-the-making
sorry and thank you for your help (i'm over in NY, GMT -5), this is very close to what i am looking for; (and have mostly re-implemented via JMS in a fairly large hack)…

but do have a few questions (none of which need to be answered soon):

workflow:
start -> JMS to somewhere -> recv task -> loop to start or end

2 problems

1)
if the other workflow / service task is not active, it will have to actually be invoked (since jms just sends messages) (or does it have to be invoked once and start in a recv task state?)

2)

the recv task, since it is just a wait state that can be continued via recving a message, how can it be changed to obtain return values through the message.

I would much rather use this model above the one that I currently have, the receive task is much clearer than how I have implemented the JMS kludge.

(2 elaborated)

lets say:
workflow 1 = start -> complicated process -> signal to recvTask -> end
workflow 2 = start -> JMS to WF1 -> recv task -> loop to start or end or BRANCH based on return value

how can the return value be obtained by workflow 1? this is significant for the case where WF2 is a larger controller that has a lot of logic (lets say user registration), and WF1 is a smaller workflow that does a specific task (write user info to a DB)

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
sorry and thank you for your help (i'm over in NY, GMT -5),
GMT+2 here if you take DST into account.

this is very close to what i am looking for; (and have mostly re-implemented via JMS in a fairly large hack)…
So you see, there are other solutions 😉

but do have a few questions (none of which need to be answered soon):
No problem, lets stay in the flow now

if the other workflow / service task is not active, it will have to actually be invoked (since jms just sends messages) (or does it have to be invoked once and start in a recv task state?)
Do not think in workflow/service tasks for this. Think in 'something' needs to be done. JMS indeed just sends messages, but there is an MDB that receives the messages. This would normally do the work and what work is dependent on what you implement there. You can make a generic mdb that starts a workflow, based on information IN the message, or just runs some javacode (sleep() ;-)) Nothing fancy.

the recv task, since it is just a wait state that can be continued via recving a message, how can it be changed to obtain return values through the message.
There is this great documentation thing (userguide apidocs) and examples etc…

Just add this in the 'callback code' right before you signal the execution. You could have the mdb that does the work execute this code if you have access to the engine, but you could also have a separate 'receiving' mdb that executes this. In the latter case you have to put the 'response variables' in the message.

I would much rather use this model above the one that I currently have, the receive task is much clearer than how I have implemented the JMS kludge.
I know 😉

rmbiplob
Champ in-the-making
Champ in-the-making
Nice topic..Thanks

coner
Champ in-the-making
Champ in-the-making
i understand how to use setVariable and getVariable and can pass the required parameters to the remote/code/workflow via JMS in the message text.

i mean when i call the signal to get the primary code resumed how can parameters actually be passed here:
runtimeService.signal(execution.getId());
or am i just wrong and i can pass things via;
execution.setVariable() etc.

i would prefer to only have to MDB out, and use the signal() method to return back to the WF.


edit:
i have been trying to test the following:
*SimplePrint does:

int count = Integer.parseInt((String) exec.getVariable("inputVar"));
System.err.println(""+count);
exec.setVaraible("inputVar", ""+(count+1));
Thread.sleep(250);

[img]http://static.inky.ws/image/550/image.jpg[/img]
the above simply fails to work properly.

VS

[img]http://static.inky.ws/image/551/image.jpg[/img]
the above crashes (stack overflow)

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
or am i just wrong and i can pass things via;
execution.setVariable() etc.

Correct
i would prefer to only have to MDB out, and use the signal() method to return back to the WF.
I do not get what you mean by this…

the above simply fails to work properly.
But what does it do? stay in the receive task? Blow up? Solve world hunger 😉

Create a small maven project with a unit test and bpmn xml in it and add it to this topic. Then I can have a look.

coner
Champ in-the-making
Champ in-the-making
"fails to work properly"

essentially i would like for it to hit the recvTask -> at which point i'm not signaling it anywhere -> thus it should time out via the border timer.

this is not what happens, the process completes after only printing out 1 loop iteration, it does not seem to time out.

maybe this is the issue; when a recv task is hit, and this is run in eclipse, does the process simply end? or will it hang there?

shouldn't it be possible to use recv tasks with border timers? T.T



i haven't been using maven, but the attached is the xml of the model, i've tried with cancelActivity = true and false


*tried uploading as .xml, .xml2, .txt, without extension; says it is not allowed T.T


<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="Breaker_Process" name="Breaker_Process">
    <documentation>Place documentation for the 'Breaker' process here.</documentation>
    <startEvent id="startevent1" name="Start"></startEvent>
    <serviceTask id="servicetask1" name="SimplePrint" activiti:class="breakers.SimplePrint"></serviceTask>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway" default="flow3"></exclusiveGateway>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="START" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow3" name="LOOP" sourceRef="exclusivegateway1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow4" name="END" sourceRef="exclusivegateway1" targetRef="endevent1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${inputVar==""}]]></conditionExpression>
    </sequenceFlow>
    <receiveTask id="receivetask1" name="Receive Task"></receiveTask>
    <sequenceFlow id="flow5" name="" sourceRef="servicetask1" targetRef="receivetask1"></sequenceFlow>
    <sequenceFlow id="flow6" name="NEVER TAKEN" sourceRef="receivetask1" targetRef="exclusivegateway1"></sequenceFlow>
    <boundaryEvent id="boundarytimer1" name="" cancelActivity="true" attachedToRef="receivetask1">
      <timerEventDefinition>
        <timeDuration>PT5S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <sequenceFlow id="flow7" name="PT5S TIMEOUT" sourceRef="boundarytimer1" targetRef="exclusivegateway1"></sequenceFlow>
  </process>
</definitions>

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
maybe this is the issue; when a recv task is hit, and this is run in eclipse, does the process simply end? or will it hang there?

If it is in a unit test (please send that as well then) the receive task will still be in the db, so the process does not end, but you unit test ends. You can check this by adding a sleep of a few seconds more than the service task would take and than run the code that would be in the callback. If that does not work there most likely is a bug. But I'll give it a try tomorrow

coner
Champ in-the-making
Champ in-the-making
it isn't actually in a unit test -> it should just print out over and over again (1 2 3 4 5 6…)
but instead it prints 1 and stops.

i can see the job sitting in the activiti-probe UI but it seems to have ignored the border timer completely.