cancel
Showing results for 
Search instead for 
Did you mean: 

blocking in user task complete

zivac
Champ in-the-making
Champ in-the-making
Hello everybody.
First post to the forum.

I hope someone will be able to help us.
We are trying to use Activiti for business processes in our application.
We are using Activiti through API (we are not usign Activiti Explorer etc.)

In a business process in question we have a user task which is basically
a file upload (user sets a file for processing). Immediately following is a
service task which processes the given file. The service task can sometimes last
very long (minutes and potentially hours).

The problem occurs when a user clicks in our user interface to submit the
task form which triggers task complete method to be executed.
Complete method seems to execute next task in business process flow (service task)
and returns from execution only after the service task has ended.
This causes our web application to wait after submit for prolonged periods of time.

How should we deal with this problem?
We have considered running complete() or the service task in a different thread
but we are not sure if that is the "correct" solution.
Are we doing something completely wrong?
What is the best and correct way of doing this?

Thanks in advance
9 REPLIES 9

frederikherema1
Star Contributor
Star Contributor
Hi,

That's the way activiti works. it takes the caller's thread and executes the process untill the next wait-state (eg. task, receive, end). So indeed, a servicetask after a usertask.complete() will be executed in the caller's thread.

What you need are "asynchronous continuations", which return the caller's thread and runs the rest of the process in another thread (jobexecutor, pooled). Unfortunatly, this is not supported yet in activiti. Workaround is to put a boundry timer event of 1second (or 0 seconds) on a dummy waitstate which, when triggered, continues the flow towards the service-task. This way, this servicetask will be executed with an tread inthe jobExecutor's pool.

zivac
Champ in-the-making
Champ in-the-making
Thank you very much for your response.

We have another problem 😕

The boundry timer event seems to get triggered more than once
if the service task it triggers lasts longer. Period of firing
seems to be exactly 5 minutes. It looks like it is hard coded somewhere.

Here is the example bmpn20.xml:

<?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="helloworld" name="helloworld">
    <startEvent id="startevent6" name="Start"></startEvent>
    <userTask id="usertask10" name="Prvi" activiti:assignee="admin"></userTask>
    <userTask id="usertask11" name="Drugi" activiti:assignee="admin"></userTask>
    <endEvent id="endevent6" name="End"></endEvent>
    <sequenceFlow id="flow20" name="" sourceRef="startevent6" targetRef="usertask10"></sequenceFlow>
    <sequenceFlow id="flow22" name="" sourceRef="usertask11" targetRef="endevent6"></sequenceFlow>
    <receiveTask id="receivetask1" name="Receive Task"></receiveTask>
    <serviceTask id="servicetask1" name="Service Task" activiti:expression="${waitProcessFinish.wait(execution,400)}"></serviceTask>
    <sequenceFlow id="flow27" name="" sourceRef="usertask10" targetRef="receivetask1"></sequenceFlow>
    <sequenceFlow id="flow29" name="" sourceRef="servicetask1" targetRef="usertask11"></sequenceFlow>
    <boundaryEvent id="boundarytimer1" name="" cancelActivity="true" attachedToRef="receivetask1">
      <timerEventDefinition>
        <timeDuration>PT10S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <sequenceFlow id="flow30" name="" sourceRef="boundarytimer1" targetRef="servicetask1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_helloworld">
    <bpmndi:BPMNPlane bpmnElement="helloworld" id="BPMNPlane_helloworld">
      <bpmndi:BPMNShape bpmnElement="startevent6" id="BPMNShape_startevent6">
        <omgdc:Bounds height="55" width="55" x="161" y="299"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask10" id="BPMNShape_usertask10">
        <omgdc:Bounds height="55" width="105" x="141" y="140"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask11" id="BPMNShape_usertask11">
        <omgdc:Bounds height="55" width="105" x="525" y="170"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent6" id="BPMNShape_endevent6">
        <omgdc:Bounds height="55" width="55" x="590" y="300"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="receivetask1" id="BPMNShape_receivetask1">
        <omgdc:Bounds height="55" width="105" x="310" y="170"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="servicetask1" id="BPMNShape_servicetask1">
        <omgdc:Bounds height="55" width="105" x="350" y="360"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="boundarytimer1" id="BPMNShape_boundarytimer1">
        <omgdc:Bounds height="20" width="20" x="390" y="200"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow20" id="BPMNEdge_flow20">
        <omgdi:waypoint x="216" y="326"></omgdi:waypoint>
        <omgdi:waypoint x="141" y="167"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow22" id="BPMNEdge_flow22">
        <omgdi:waypoint x="630" y="197"></omgdi:waypoint>
        <omgdi:waypoint x="590" y="327"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow27" id="BPMNEdge_flow27">
        <omgdi:waypoint x="246" y="167"></omgdi:waypoint>
        <omgdi:waypoint x="310" y="197"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow29" id="BPMNEdge_flow29">
        <omgdi:waypoint x="455" y="387"></omgdi:waypoint>
        <omgdi:waypoint x="525" y="197"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow30" id="BPMNEdge_flow30">
        <omgdi:waypoint x="100" y="40"></omgdi:waypoint>
        <omgdi:waypoint x="350" y="387"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Service task is just a dummy method that waits for 400 ms (longer than 5 min).
It got executed 3 times before throwing an exception (ActivitiOptimisticLockingException).
If we set the waiting period below 5 mins it executes once without problems.

Please help.
Thanks

jbarrez
Star Contributor
Star Contributor
Putting a timer on a service task is tricky, as it not very clear which transaction will 'win' (there will be a transaction for the service task and for the timer).
I would advise not to put a timer on a service task, and use native Java timer there, which when fired takes an sequence flow going out of the service task.

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
@Joram,

Is the advice you give because of the way Activiti works or in general? I'd think that the engine should be able to cope with this some at some point in the (distant?) future, or ….

jbarrez
Star Contributor
Star Contributor
@Ronald: the thing is: in theory it could work with the current impl. But you never know how fast a service task executed and which transaction will be first committed to the database. However, I do believe this is something we should fix in the engine (eg by *not* using jobs for a timer on an automatic step).

michael_amann
Champ in-the-making
Champ in-the-making
Hi there,

we are currently facing the same issue with Activiti 5.10. Sending the task.complete(<taskId>) blocks the thread until the following service tasks are completed as well. We also tried to add an intermediate signal event after the user task to avoid the blocking. This works, but as soon as we send the signal event, the same problem occurs - the sending thread is blocked until the following service task is complete.

Does anybody have a solution for this problem? We are currently experimenting with Activiti in order to use it in a large application and it would be great if we could at least workaround this issue.

Regards
Michael

jbarrez
Star Contributor
Star Contributor
Yes, this is the normal way of how Activiti works.
To make the thread return right after the task, you need to read up on 'async continuations', which are exactly created for that use case:
http://activiti.org/userguide/index.html#asyncContinuations

michael_amann
Champ in-the-making
Champ in-the-making
Thank's for the reply.

In the meantime I figured out why it didn't work on my project. The issue was that the async attribute was not evaluated.

Setting the property jobExecutorActivate to "true" solved the problem.

The property can be found in the applicationContext.xml File (if you're in a Spring project)

  <property name="jobExecutorActivate" value="true" />

Regards
Michael

jbarrez
Star Contributor
Star Contributor
Indeed, that's correct.

Thanks for posting the solution!