14 Replies Latest reply on Jan 31, 2012 4:10 PM by melc

    saving state after workitem

    pmancham

      I created a workitem to call a web-service. I added the workitem to a workflow and I would like the process state saved immediately after the work item is executed. (So, that if I had to load the workflow after a server crash, the workflow will start from a point where it does not have to make same web-service call again - if it already called that webserivce before server crash)

       

      What should I have in my WorkItemHandler.executeWorkItem() method in order to achieve this?

       

      Here is another thread that discusses "when the state is saved" in general -> https://community.jboss.org/thread/173809

        • 1. Re: saving state after workitem
          melc

          Hello,

          What if the server crashes while calling the web service just before calling it or just before the response is received?

          To overcome such a scenario, you would need to persist the work item before calling the web service.

           

          Generally when you create a workitem, in order to have its state persisted, by the engine, you need to run it asynchronously, i.e. within a new thread.

          When the system is recovered you would need to re run this work item.

           

          If you want to perist the state of the process right after the web service is called, in other words when the work item is completed, you can simply call another asynchronous work item right after the call of you web service work item. In addition a human task could be used, if it makes sense.

           

          However, what if the system goes down before completing the ws work item but after the ws call?

          Then you need to apply some kind of logic in your system that runs the ws call within a transaction and modifies some kind of state, that you will check when trying to rerun the work item after a process recovery.

          • 2. Re: saving state after workitem
            pmancham

            Thank you. I am looking into all these options. First one I am trying is to have a signal event right after the workitem. The signal event will cause the workflow state to persist and application will trigger the signal after some sleep time of 10 to 15 seconds.

             

            Signal event however, is giving a problem between eclipse & guvnor oryx designers. I created another discussion thread for that.

            • 3. Re: saving state after workitem
              pmancham

              I have a workflow with

               

              start -> script task1 -> workitem1 ->signal -> script task2 -> workitem2 -> end

               

              If state is saved at signal, and at script task2 server crashes, then, upon restarting server, I have to load all processIds that server was running (probably from database) and also load the last signal to be able to correctly start these processes.

               

              StatefulKnowledgeSession ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(sid, kbase, config, env); [This wont start the process from where it left off]

              ProcessInstance pi = (ProcessInstance) ksession.getProcessInstance(pid);

              pi.signalEvent(signal, signalData); // I have to store these in some store to be able to restart correctly after reload

              • 4. Re: saving state after workitem
                melc

                Hi,

                When you reach the signal, your process will persist and wait for that signal. The only place to see that a signal has been reached by an instance of your process, is the NodeInstanceLog table. If you examine the entries you can find out whether a signal has completed or not. Then you would have to somehow figure out the ref of the signal and make a call as you would from your external process and continue.  So if i understand correctly you want your process to wait at the signal and somehow an external event is called by your system to continue..

                 

                Otherwise if you only try to persist just make workitem1 asynchronous and omit the signal part i.e. start->script1->workitem1->script2->workitem2->end. That will persist your work item until it gets completed. So if it fails while running you can get the work item from WorkItemInfo and rerun it , otherwise if it completes the process will continue to script2 and so on.

                 

                please correct me if i havent understood your intention

                • 5. Re: saving state after workitem
                  pmancham

                  >>>> Otherwise if you only try to persist just make workitem1 asynchronous and omit the signal part i.e. start->script1->workitem1->script2->workitem2->end. That will persist your work item >>>> until it gets completed. So if it fails while running you can get the work item from WorkItemInfo and rerun it , otherwise if it completes the process will continue to script2 and so on.

                   

                  I want the above. I will try asynchronous execution of workitem and test the persistence. When it fails, you say, that I can get the work item from WorkItemInfo and rerun it. I have few questions with that:

                   

                  a) If process fails at script2, that means workitem1 is complete (& its entry will be deleted from workiteminfo table - isnt it?). How would l restart the process from script2?

                  b) If workitem1 is not deleted from workiteminfo & I attempt to rerun it - would the process instance skip execution of the workitem1 and start directly at script2 (since it knows that workitem1 was complete) or would the process instance just rerun workitem1 meaning process restarts from workitem1 & not script2

                   

                  Would you be able to share the bootstrap code that you have written to load and run workitems after process loads?

                  • 6. Re: saving state after workitem
                    pmancham

                    One more problem - after (a) & (b) above

                     

                    (c) I had 2 workitems. First one was inserted & updated. Second one was never inserted & the process exited. Why? [Queries can be seen from logs I pasted below]

                     

                    My sample test case

                     

                    BPMN: (Also attached picture below)

                     

                    <?xml version="1.0" encoding="UTF-8"?>

                    <definitions id="Definition"

                                 targetNamespace="http://www.jboss.org/drools"

                                 typeLanguage="http://www.java.com/javaTypes"

                                 expressionLanguage="http://www.mvel.org/2.0"

                                 xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"

                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                                 xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"

                                 xmlns:g="http://www.jboss.org/drools/flow/gpd"

                                 xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"

                                 xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"

                                 xmlns:di="http://www.omg.org/spec/DD/20100524/DI"

                                 xmlns:tns="http://www.jboss.org/drools">

                     

                     

                      <itemDefinition id="_result1Item" structureRef="String" />

                      <itemDefinition id="_result2Item" structureRef="String" />

                      <itemDefinition id="_retry1Item" structureRef="Integer" />

                      <itemDefinition id="_retry2Item" structureRef="Integer" />

                     

                     

                      <process processType="Private" isExecutable="true" id="com.sample.bpmn.saveStateExample" name="Sample Process" tns:packageName="testPackage" >

                     

                     

                        <!-- process variables -->

                        <property id="result1" itemSubjectRef="_result1Item"/>

                        <property id="result2" itemSubjectRef="_result2Item"/>

                        <property id="retry1" itemSubjectRef="_retry1Item"/>

                        <property id="retry2" itemSubjectRef="_retry2Item"/>

                     

                     

                        <!-- nodes -->

                        <startEvent id="_1" name="StartProcess" />

                        <scriptTask id="_3" name="Script" scriptFormat="http://www.java.com/java" >

                          <script>System.out.println("********** MESSAGE1 *************");

                    String message1 = ((String) kcontext.getVariable("result1"));

                    System.out.println(message1);

                    message1 = message1 + " World";

                    kcontext.setVariable("result1", message1);

                    System.out.println("********** END1 *************");</script>

                        </scriptTask>

                        <scriptTask id="_5" name="Script" scriptFormat="http://www.java.com/java" >

                          <script>System.out.println("********** MESSAGE2 *************");

                    String message2 = ((String) kcontext.getVariable("result1"));

                    System.out.println(message2);

                    System.out.println("********** END2 *************");</script>

                        </scriptTask>

                        <endEvent id="_6" name="End" >

                            <terminateEventDefinition/>

                        </endEvent>

                        <task id="_9" name="SaveState" tns:taskName="SaveState" >

                          <ioSpecification>

                            <inputSet>

                            </inputSet>

                            <outputSet>

                            </outputSet>

                          </ioSpecification>

                        </task>

                        <task id="_10" name="SaveState" tns:taskName="SaveState" >

                          <ioSpecification>

                            <inputSet>

                            </inputSet>

                            <outputSet>

                            </outputSet>

                          </ioSpecification>

                        </task>

                     

                     

                        <!-- connections -->

                        <sequenceFlow id="_9-_3" sourceRef="_9" targetRef="_3" />

                        <sequenceFlow id="_10-_5" sourceRef="_10" targetRef="_5" />

                        <sequenceFlow id="_5-_6" sourceRef="_5" targetRef="_6" />

                        <sequenceFlow id="_1-_9" sourceRef="_1" targetRef="_9" />

                        <sequenceFlow id="_3-_10" sourceRef="_3" targetRef="_10" />

                     

                     

                      </process>

                     

                     

                      <bpmndi:BPMNDiagram>

                        <bpmndi:BPMNPlane bpmnElement="com.sample.bpmn.saveStateExample" >

                          <bpmndi:BPMNShape bpmnElement="_1" >

                            <dc:Bounds x="55" y="106" width="48" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNShape bpmnElement="_3" >

                            <dc:Bounds x="136" y="208" width="117" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNShape bpmnElement="_5" >

                            <dc:Bounds x="313" y="295" width="96" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNShape bpmnElement="_6" >

                            <dc:Bounds x="341" y="389" width="48" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNShape bpmnElement="_9" >

                            <dc:Bounds x="321" y="111" width="100" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNShape bpmnElement="_10" >

                            <dc:Bounds x="471" y="196" width="100" height="48" />

                          </bpmndi:BPMNShape>

                          <bpmndi:BPMNEdge bpmnElement="_9-_3" >

                            <di:waypoint x="371" y="135" />

                            <di:waypoint x="194" y="232" />

                          </bpmndi:BPMNEdge>

                          <bpmndi:BPMNEdge bpmnElement="_10-_5" >

                            <di:waypoint x="521" y="220" />

                            <di:waypoint x="361" y="319" />

                          </bpmndi:BPMNEdge>

                          <bpmndi:BPMNEdge bpmnElement="_5-_6" >

                            <di:waypoint x="361" y="319" />

                            <di:waypoint x="365" y="413" />

                          </bpmndi:BPMNEdge>

                          <bpmndi:BPMNEdge bpmnElement="_1-_9" >

                            <di:waypoint x="79" y="130" />

                            <di:waypoint x="371" y="135" />

                          </bpmndi:BPMNEdge>

                          <bpmndi:BPMNEdge bpmnElement="_3-_10" >

                            <di:waypoint x="194" y="232" />

                            <di:waypoint x="521" y="220" />

                          </bpmndi:BPMNEdge>

                        </bpmndi:BPMNPlane>

                      </bpmndi:BPMNDiagram>

                     

                     

                    </definitions>

                     

                     

                    SaveState WorkItem:

                     

                    public class SaveStateWorkItemHandler implements WorkItemHandler {

                        @Override

                        public void executeWorkItem(WorkItem workItem, WorkItemManager workItemManager) {

                            System.out.println("******** START SAVE-STATE SLEEP *************");

                            final WorkItem myWorkItem = workItem;

                            final WorkItemManager myWorkItemManager = workItemManager;

                            Thread t = new Thread(new Runnable() {

                                @Override

                                public void run() {

                                    try {

                                        for (int i=0; i<10; i++) {

                                            System.out.println("i = " + i);

                                            Thread.sleep(2000);

                                        }

                                        System.out.println("******** END SAVE-STATE SLEEP *************");

                                        myWorkItemManager.completeWorkItem(myWorkItem.getId(), null);

                                    } catch (InterruptedException e) {

                                        System.out.println("Exception while sleeping in the thread");

                                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                                    }

                                }

                            });

                            t.start();

                            System.out.println("******** END SAVE-STATE *************");

                        }

                     

                     

                        @Override

                        public void abortWorkItem(WorkItem workItem, WorkItemManager workItemManager) {

                            //Do Nothing.

                            workItemManager.abortWorkItem(workItem.getId());

                        }

                    }

                     

                     

                    Servlet that starts the workflow:

                     

                    Properties properties = new Properties();

                            properties.put("drools.processInstanceManagerFactory", "org.jbpm.persistence.processinstance.JPAProcessInstanceManagerFactory");

                            properties.put("drools.processSignalManagerFactory", "org.jbpm.persistence.processinstance.JPASignalManagerFactory");

                            KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration(properties);

                            if (sid == -1) {

                                EntityManagerFactory emf =

                                        Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");

                                Environment env = KnowledgeBaseFactory.newEnvironment();

                                env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);

                                //env.set(EnvironmentName.TRANSACTION_MANAGER,)

                                // create a new knowledge session that uses JPA to store the runtime state

                                StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, config, env);

                                JPAWorkingMemoryDbLogger dblogger = new JPAWorkingMemoryDbLogger(ksession);

                                KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newThreadedFileLogger(ksession, "test", 1000);

                                ksession.getWorkItemManager().registerWorkItemHandler("SaveState", new SaveStateWorkItemHandler());

                                int sessionId = ksession.getId();

                                // invoke methods on your method here

                                ProcessInstance pi = (ProcessInstance) ksession.startProcess(processId, params);

                                System.out.println("Process started ... sessionId = " + sessionId + " processId = " + pi.getId());

                                  

                                //Ignore the lines below - Added it for some other workflow I was testing

                                try {

                                    System.out.println("Sleeping for 15 seconds");

                                    Thread.sleep(15000);

                                } catch (InterruptedException e) {

                                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                                }

                                pi.signalEvent(signal, signalData);

                                System.out.println("Signaled event");

                     

                     

                    Logs:

                     

                    11:48:45,308 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select SESSIONINFO_ID_SEQ.nextval from dual

                     

                     

                    11:48:45,308 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into SessionInfo (lastModificationDate, rulesByteArray, startDate, OPTLOCK, id) values (?, ?, ?, ?, ?)

                     

                     

                    11:48:45,324 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,324 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,324 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,324 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,340 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,340 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,340 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,340 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,340 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: select WORKITEMINFO_ID_SEQ.nextval from dual

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) ******** START SAVE-STATE SLEEP *************

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) ******** END SAVE-STATE *************

                     

                     

                    11:48:45,355 INFO  [stdout] (Thread-69) i = 0

                     

                     

                    11:48:45,355 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: update SessionInfo set lastModificationDate=?, rulesByteArray=?, startDate=?, OPTLOCK=? where id=? and OPTLOCK=?

                     

                     

                    11:48:45,371 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into ProcessInstanceInfo (lastModificationDate, lastReadDate, processId, processInstanceByteArray, startDate, state, OPTLOCK, InstanceId) values (?, ?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,371 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,371 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,386 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,386 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,386 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,386 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into VariableInstanceLog (log_date, processId, processInstanceId, value, variableId, variableInstanceId, id) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,402 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into ProcessInstanceLog (end_date, processId, processInstanceId, start_date, id) values (?, ?, ?, ?, ?)

                     

                     

                    11:48:45,402 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into NodeInstanceLog (log_date, nodeId, nodeInstanceId, nodeName, processId, processInstanceId, type, id) values (?, ?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,402 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into NodeInstanceLog (log_date, nodeId, nodeInstanceId, nodeName, processId, processInstanceId, type, id) values (?, ?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,402 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into NodeInstanceLog (log_date, nodeId, nodeInstanceId, nodeName, processId, processInstanceId, type, id) values (?, ?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,418 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: insert into WorkItemInfo (creationDate, name, processInstanceId, state, OPTLOCK, workItemByteArray, workItemId) values (?, ?, ?, ?, ?, ?, ?)

                     

                     

                    11:48:45,418 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: update ProcessInstanceInfo set lastModificationDate=?, lastReadDate=?, processId=?, processInstanceByteArray=?, startDate=?, state=?, OPTLOCK=? where InstanceId=? and OPTLOCK=?

                     

                     

                    11:48:45,418 INFO  [stdout] (http--0.0.0.0-8080-4) Hibernate: update WorkItemInfo set creationDate=?, name=?, processInstanceId=?, state=?, OPTLOCK=?, workItemByteArray=? where workItemId=? and OPTLOCK=?

                     

                     

                    11:48:45,433 INFO  [stdout] (http--0.0.0.0-8080-4) Process started ... sessionId = 35 processId = 818

                     

                     

                    11:48:45,433 INFO  [stdout] (http--0.0.0.0-8080-4) Sleeping for 15 seconds

                     

                     

                    11:48:47,353 INFO  [stdout] (Thread-69) i = 1

                     

                     

                    11:48:49,366 INFO  [stdout] (Thread-69) i = 2

                     

                     

                    11:48:51,363 INFO  [stdout] (Thread-69) i = 3

                     

                     

                    11:48:53,361 INFO  [stdout] (Thread-69) i = 4

                     

                     

                    11:48:55,358 INFO  [stdout] (Thread-69) i = 5

                     

                     

                    11:48:57,355 INFO  [stdout] (Thread-69) i = 6

                     

                     

                    11:48:59,353 INFO  [stdout] (Thread-69) i = 7

                     

                     

                    11:49:00,414 INFO  [stdout] (http--0.0.0.0-8080-4) Signaled event

                     

                     

                    11:49:01,350 INFO  [stdout] (Thread-69) i = 8

                     

                     

                    11:49:03,348 INFO  [stdout] (Thread-69) i = 9

                     

                     

                    11:49:05,361 INFO  [stdout] (Thread-69) ******** END SAVE-STATE SLEEP *************

                     

                     

                    11:49:05,361 INFO  [stdout] (Thread-69) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:05,361 INFO  [stdout] (Thread-69) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:05,361 INFO  [stdout] (Thread-69) ********** MESSAGE1 *************

                     

                     

                    11:49:05,376 INFO  [stdout] (Thread-69) Hello

                     

                     

                    11:49:05,376 INFO  [stdout] (Thread-69) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) ********** END1 *************

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) Hibernate: select WORKITEMINFO_ID_SEQ.nextval from dual

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) ******** START SAVE-STATE SLEEP *************

                     

                     

                    11:49:05,392 INFO  [stdout] (Thread-69) ******** END SAVE-STATE *************

                     

                     

                    11:49:05,408 INFO  [stdout] (Thread-70) i = 0

                     

                     

                    11:49:07,405 INFO  [stdout] (Thread-70) i = 1

                     

                     

                    11:49:09,402 INFO  [stdout] (Thread-70) i = 2

                     

                     

                    11:49:11,400 INFO  [stdout] (Thread-70) i = 3

                     

                     

                    11:49:13,397 INFO  [stdout] (Thread-70) i = 4

                     

                     

                    11:49:15,395 INFO  [stdout] (Thread-70) i = 5

                     

                     

                    11:49:17,392 INFO  [stdout] (Thread-70) i = 6

                     

                     

                    11:49:19,390 INFO  [stdout] (Thread-70) i = 7

                     

                     

                    11:49:21,403 INFO  [stdout] (Thread-70) i = 8

                     

                     

                    11:49:23,400 INFO  [stdout] (Thread-70) i = 9

                     

                     

                    11:49:25,397 INFO  [stdout] (Thread-70) ******** END SAVE-STATE SLEEP *************

                     

                     

                    11:49:25,397 INFO  [stdout] (Thread-70) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:25,397 INFO  [stdout] (Thread-70) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:25,397 INFO  [stdout] (Thread-70) ********** MESSAGE2 *************

                     

                     

                    11:49:25,413 INFO  [stdout] (Thread-70) Hello World

                     

                     

                    11:49:25,413 INFO  [stdout] (Thread-70) ********** END2 *************

                     

                     

                    11:49:25,413 INFO  [stdout] (Thread-70) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:25,413 INFO  [stdout] (Thread-70) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:25,413 INFO  [stdout] (Thread-70) Hibernate: select hibernate_sequence.nextval from dual

                     

                     

                    11:49:25,429 INFO  [stdout] (Thread-70) Hibernate: select processins0_.id as id57_, processins0_.end_date as end2_57_, processins0_.processId as processId57_, processins0_.processInstanceId as processI4_57_, processins0_.start_date as start5_57_ from ProcessInstanceLog processins0_ where processins0_.processInstanceId=? and (processins0_.end_date is null)

                     

                     

                    11:49:25,444 INFO  [stdout] (Thread-70) Hibernate: select processins0_.InstanceId as col_0_0_ from ProcessInstanceInfo processins0_ inner join EventTypes eventtypes1_ on processins0_.InstanceId=eventtypes1_.InstanceId where eventtypes1_.element=?

                     

                     

                     

                    saveStateSample.GIF

                    • 7. Re: saving state after workitem
                      melc

                      Hello,

                      So for the following case,

                      start->workItem1->script1->workItem2->script2->end

                       

                      a) Yes by reaching script2 the workitem1 is completed and its entry is deleted from the workiteminfo table. It also means that workitem2 has executed and by failing at script2 you can only examine the NodeInstanceLog table to figure out what has happened and maybe take some action. However  i think the process instance at that stage will not resume since there will be no associated workitem persisted to execute/complete.

                      b) If workitem1 completes then it is deleted from the workiteminfo. But generally if you pickup a persisted work item (other than a work item associated with a human task....because a human task has an entry in the task table as well and needs a bit more care i.e. whether the task has completed or not etc) from the database you can either re execute it or complete it. These are achieved by quering the database table workiteminfo retrieving the object associated with the work item you want and calling either

                       

                      YourWorkItemHandler yourWorkItemHandler = new YourWorkItemHandler();

                      yourWorkItemHandler.executeWorkItem(workItemFromDB, ksession.getWorkItemManager());

                      to re execute the work item

                      or complete it

                      ksession.getWorkItemManager().completeWorkItem(workItemFromDB, workItemFromDB.getParameters()/*or some other params etc*/);

                       

                      The following bootstrap code can be used for non human task work items that have not completed (i.e. system crashed while running) and choosing to re execute them, as well as human task work items that have completed and the system crashed right after the human task completion but before entering the next wait point.

                       

                      private void bootstrapForWorkItems() {

                              EntityManagerFactory emf = null;

                              EntityManager tempEntityManager = null;

                              List results = null;

                              try {

                                  emf = (EntityManagerFactory) ksession.getEnvironment().get(EnvironmentName.ENTITY_MANAGER_FACTORY);

                                  tempEntityManager = emf.createEntityManager();

                                  results = tempEntityManager.createNativeQuery("SELECT w.* FROM WorkItemInfo w inner join Task t on t.workItemId=w.workItemId where t.status='Completed' union SELECT w.* FROM WorkItemInfo w  where name <> 'Human Task'", WorkItemInfo.class).getResultList();

                              } finally {

                                  if (tempEntityManager != null) {

                                      tempEntityManager.close();

                                  }

                              }

                              if (results != null) {

                                  for (Object resultObject : results) {

                                      WorkItemInfo workItemInfo = (WorkItemInfo) resultObject;

                                      WorkItem workItem = workItemInfo.getWorkItem(ksession.getEnvironment());

                                      if (workItem.getName().equals("YourWorkItem1")) {

                                          YourWorkItem1WorkItemHandler yourWorkItem1WorkItemHandler = new YourWorkItem1WorkItemHandler(ksession);

                                          yourWorkItem1WorkItemHandler.executeWorkItem(workItem, ksession.getWorkItemManager());

                                      }

                                      if (workItem.getName().equals("YourWorkItem2")) {

                      YourWorkItem2WorkItemHandler yourWorkItem1WorkItemHandler = new YourWorkItem2WorkItemHandler(ksession);

                                          YourWorkItem2WorkItemHandler.executeWorkItem(workItem, ksession.getWorkItemManager());

                                      } else if (workItem.getName().equals("Human Task")) {

                      /*i'm not sure about the workItem.getParameters() here, might be getting the params of the previous human task....might need a little fixing*/

                                          ksession.getWorkItemManager().completeWorkItem(workItem.getId(), workItem.getParameters());

                                          //or

                                          //call correct workitemhandler for this task and re execute

                                      }

                                  }//for - results

                              }//if - results

                          }//method

                       

                      Of course in some cases you may choose to act differently i.e.instead of re executing a work item, complete it because you checked your business logic (i.e. checked your system's database) and realised that data has been commited or web service has been called but the jbpm engine system crashed right before erasing the workitem etc.

                       

                      c) By quickly looking at your code and  log  i see that workitem1 executed then script1, followed by workitem2 and script2 .... so i think it went fine. I'm not sure i get the problem.

                      1 of 1 people found this helpful
                      • 8. Re: saving state after workitem
                        pmancham

                        Thank you for taking the time.

                         

                        c) The workflow ran fine. The problem is workitem2 entry was never made in database before the process exited. Shouldn't the entry for workitem2 be made before it starts executing (the for loop)?

                        • 9. Re: saving state after workitem
                          melc

                          I see, well it should persist by the time the main thread exits the executeWorkItem method, it is then when the transaction commits.

                          Have you tried to check the database while the 2nd loop was running or by using a breakpoint to hold the execution?

                          • 10. Re: saving state after workitem
                            pmancham

                            When I do debugging (or) add timers after workitems the entries are created & then deleted from database, but, when I run it without debug (or) timers entry for second workitem is not made. To confirm it, I changed jpapersistencecontext class and commented out remove(WorkItemInfo) method. After the commented out remove method, with timers I see 2 workitems and without timer I see only 1 workitem.

                            • 11. Re: saving state after workitem
                              pmancham

                              what does adding a timer do? Why doesnt it persist if there is no timer before the end node?

                              • 12. Re: saving state after workitem
                                melc

                                Hi,

                                I tried out your code on jboss7, mysql and it worked fine with the following changes applied,

                                 

                                1. Introduce a KnowledgeRuntime field in your handler,

                                public class SaveStateWorkItemHandler implements WorkItemHandler {

                                    private KnowledgeRuntime session;

                                 

                                    public SaveStateWorkItemHandler() {

                                    }

                                 

                                    public SaveStateWorkItemHandler(KnowledgeRuntime session) {

                                        this();

                                       this.session = session;

                                    }

                                ......

                                 

                                2. Complete the work item in your SaveStateWorkItemHandler as follows,

                                ....

                                System.out.println("******** END SAVE-STATE SLEEP *************");

                                session.getWorkItemManager().completeWorkItem(myWorkItem.getId(), null);

                                 

                                3. Register your handler accordingly,

                                ksession.getWorkItemManager().registerWorkItemHandler("SaveState", new SaveStateWorkItemHandler(ksession));

                                • 13. Re: saving state after workitem
                                  pmancham

                                  Yes, it works when ksession.getWorkItemManager() is used. How did you figure it out ? Thank you.

                                  • 14. Re: saving state after workitem
                                    melc

                                    Great i'm glad it worked out for you.

                                    The human task work item handler CommandBasedWSHumanTaskHandler works in a similar way.

                                    p.s. please mark question as answered so we can assist others

                                    thanks