AnsweredAssumed Answered

Handling graceful shutdown

Question asked by kelner on Apr 28, 2014
Hi,

I am trying to determine how to configure Activiti to handle the following scenario given the following example configuration:

<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
             targetNamespace="http://activiti.org/bpmn20"
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:activiti="http://activiti.org/bpmn">

  <error id="errorRollback" errorCode="rollback"/>

  <process id="createDemoProcess">

    <startEvent id="startCreate"/>
    <sequenceFlow id="_1" sourceRef="startCreate" targetRef="startTask"/>
    <sequenceFlow id="_2" sourceRef="startTask" targetRef="demoSubProcess1"/>
    <sequenceFlow id="_3" sourceRef="demoSubProcess1" targetRef="demoSubProcess2"/>
    <sequenceFlow id="_5" sourceRef="demoSubProcess2" targetRef="completionTask"/>
    <sequenceFlow id="_6" sourceRef="completionTask" targetRef="endCreate"/>

    <sequenceFlow id="_rollbackDemoSubProcess1" sourceRef="rollbackDemoSubProcess1" targetRef="rollbackDemoSubProcess2"/>
    <sequenceFlow id="_rollbackDemoSubProcess2" sourceRef="rollbackDemoSubProcess2" targetRef="rollbackDemoProcess"/>
    <sequenceFlow id="_rollbackEnd" sourceRef="rollbackDemoProcess" targetRef="endCreate"/>

    <endEvent id="endCreate"/>

    <boundaryEvent id="rollbackDemoSubProcess1" attachedToRef="demoSubProcess1" cancelActivity="true">
      <errorEventDefinition errorRef="rollback"/>
    </boundaryEvent>

    <boundaryEvent id="rollbackDemoSubProcess2" attachedToRef="demoSubProcess2" cancelActivity="true">
      <errorEventDefinition errorRef="rollback"/>
    </boundaryEvent>
   
    <boundaryEvent id="cancelDemoSubProcess1" attachedToRef="demoSubProcess1" >
      <cancelEventDefinition />
    </boundaryEvent>

    <boundaryEvent id="cancelDemoSubProcess2" attachedToRef="demoSubProcess2" >
      <cancelEventDefinition />
    </boundaryEvent>

    <boundaryEvent id="cancelRollback" attachedToRef="rollbackDemoProcess" >
      <cancelEventDefinition />
    </boundaryEvent>

    <transaction id="rollbackEnvironmentProcess" activiti:async="true">

      <startEvent id="startRollback"/>
      <sequenceFlow id="_1rollback" sourceRef="startRollback" targetRef="removeDemoSubProcess1"/>
      <sequenceFlow id="_2rollback" sourceRef="removeDemoSubProcess1" targetRef="removeDemoSubProcess2"/>
      <sequenceFlow id="_3rollback" sourceRef="removeDemoSubProcess2" targetRef="endRollback"/>
      <endEvent id="endRollback"/>

      <serviceTask
          id="removeSubProcess1"
          activiti:class="something.activiti.tasks.RemoveSubProcess1"
          activiti:async="true"
          />

      <serviceTask
          id="removeSubProcess2"
          activiti:class="something.activiti.tasks.RemoveSubProcess2"
          activiti:async="true"
          />

    </transaction>

    <transaction id="demoSubProcess1" activiti:async="true">

      <startEvent id="startDemoSubProcess1"/>
        <sequenceFlow id="_1demoSubProcess1" sourceRef="startDemoSubProcess1" targetRef="demoSubProcess11"/>
        <sequenceFlow id="_2demoSubProcess1" sourceRef="demoSubProcess11" targetRef="demoSubProcess12"/>
        <sequenceFlow id="_3demoSubProcess1" sourceRef="demoSubProcess12" targetRef="endDemoSubProcess1"/>
      <endEvent id="endDemoSubProcess1"/>

      <serviceTask
          id="demoSubProcess11"
          activiti:class="something.activiti.tasks.network.firewall.DemoSubProcess11Task"
          activiti:async="true"
          />

      <serviceTask
          id="demoSubProcess12"
          activiti:class="something.activiti.tasks.network.firewall.DemoSubProcess12Task"
          activiti:async="true"
          />

    </subProcess>

    <subProcess id="demoSubProcess2" activiti:async="true">

      <startEvent id="startDemoSubProcess2"/>
        <sequenceFlow id="_1demoSubProcess2" sourceRef="startDemoSubProcess2" targetRef="demoSubProcess21"/>
        <sequenceFlow id="_2demoSubProcess2" sourceRef="demoSubProcess21" targetRef="demoSubProcess22"/>
        <sequenceFlow id="_3demoSubProcess2" sourceRef="demoSubProcess22" targetRef="endDemoSubProcess2"/>
      <endEvent id="endDemoSubProcess2"/>

      <serviceTask
          id="demoSubProcess21"
          activiti:class="something.activiti.tasks.network.DemoSubProcess21Task"
          activiti:async="true"
          />

      <serviceTask
          id="demoSubProcess22"
          activiti:class="something.activiti.tasks.network.DemoSubProcess22Task"
          activiti:async="true"
          />

    </transaction>

    <serviceTask
        id="startTask"
        activiti:class="something.activiti.tasks.StartTask"
        activiti:async="true"
        />

    <serviceTask
        id="completionTask"
        activiti:class="something.activiti.tasks.CompletionTask"
        activiti:async="true"
        >
    </serviceTask>

  </process>

</definitions>

(also see gist: https://gist.github.com/ckelner/cbeb881e9a9f0d40b96a)

1) A process is started
2) a graceful shutdown signal is sent
3) current service task ends execution and state is written to database
4) server is brought back online and job is picked back up for completion

The problem I have right now is that I can't seem to configure execution to end during any transaction within the main process.  I recently added the cancel boundary events to the configuration and switched over from subProcess to transaction but that doesn't seem to have had an impact.  I'll be honest I don't have a strong grasp on everything presented from Activiti so I apologize for my limitation and understanding.

Currently I see this at the end of a transaction if it doesn't complete during graceful shutdown:

Timeout during shutdown of job executor. The current running jobs could not end within 60 seconds after shutdown operation.


It does seem that Activiti picks this job back up when I restart the server, which is desired, however it seems to try to "jump back" or start the process over again (I am unsure of which- it is hard to tell) and I have a database id collision which triggers the rollback.  HOWEVER, it then re-executes the job again and ends on a success (so long as I let the process run and don't kill the server a second time).

Hoping someone can help me with my config and activiti understanding.

Thanks,
ckelner

Outcomes