9 Replies Latest reply on May 30, 2012 12:09 PM by inbrain

    How to get current node instance in a workitem handler?

    affandar

      We need to persist per processinstance+nodeinstance data during the execution of a workitem. There are quite a few use cases for this:

       

      1) The workitemhandler needs to store some state that it can use to build some additional guarantees in the face of server restarts/crashes.

      E.g., in some FireMissileWorkItemHandler() I want to log the fact that the missile was already fired so that if the server crashed before jbpm hits the next persist point and the same process is restarted, the workitemhandler can lookup the state and see that it had already fired a missile. Of course this will not give us an exactly-once guarantee since the server can crash before it checkpointed but this way we give the workitem developers some more control.

       

      2) A workitem handler generates some intermediate data that should be logged/persisted.

      Here is the problem: the index for this data should be {processinstanceid, nodeid} since these are the only two things that will remain the same if the process instance is restarted after a crash. The workitemid that is available in a workitemhandler is regenerated if the workitem was executed again on a process restart. Now, within a workitemhandler I could not find any way to extract the node id of the currently executing node or the current node instance. Note that this is readily available for script tasks via kcontext.getNodeInstance(). I don't know why the same is not available for a workitem handler.

       

      In addition to the persistence scenario, another use case for a node id in workitemhandler is that a workitem handler itself needs to generate a signal to a compensation handler. In this case, I want to say something like this in the workitemhandler code:

      ksession.signalEvent("Compensate-" + current_node_id, null);

       

      Again, it requires access to the current node id.

       

      Is this an interesting scenario for the community as well? How did other folks resolve this?

       

      Thanks

        • 1. Re: How to get current node instance in a workitem handler?
          krisverlaenen

          Hi,

           

          The main reason for not exposing the node instance in the work item handler is that "in general" we believe this is not necessary in most use cases.   Giving access to the node instance in the handler would in a lot situations lead to handlers that are tightly coupled to the process instance that triggered the service invocation (kinda like how ActionHandlers worked in jBPM3), where they (imho) should be more generic and reusable accross processes.

           

          That said, I can see how access to the node instance id might be useful in some cases (without losing the genericity of the handler).  The work item currently has access to the process instance id, so you could just retrieve the process instance from the session and find the node instance that references this work item.  We could make an AbstractWorkItemHandler or a utility method that would allow you to do something like that easily.

           

          Wdyt?

           

          Kris

          • 2. Re: How to get current node instance in a workitem handler?
            affandar

            "The work item currently has access to the process instance id, so you could just retrieve the process instance from the session and find the node instance that references this work item."

             

            That actually gives me a good workaround.

             

            Re decoupling, in this case I was more interested in the node id rather than the process instance or node instance id.

             

            I think it will be useful to expose this in the base class or as a utility method. Should I go ahead and file a JIRA for this? Can also put out a patch for it..

             

            Thanks

            • 3. Re: How to get current node instance in a workitem handler?
              xmithj

              Hi Affan,

               

              I have got the same problem (your use cases are very valid). But I don’t understand your workaround. Currently the work item handler doesn’t have access to the knowledge session, so I am not sure what do you mean with “could just retrieve the process instance from the session and find…”  Could you please elaborate here?

               

              I tried injecting the knowledge session at work item creation time (effectively achieving having the ksession inside the work item handler), but then when I was testing persistence and resuming after a crash I found the retrieved ksession was not identical to the original ksession that created/started the flow, and I found myself doing complex coding to try to solve problems. When my code became more complex than necessary, I realised everything would have been very simple if I could fetch the ksession from the  WorkItemManager. However the jbpm team has decided to hide the ksession from the work item, and very likely this mean we shouldn’t try to inject the ksession inside the work item ourselves.

               

              I would be very interested to see what Kris is able to provide here.

               

              Thanks in advance,

              John.

              • 4. Re: How to get current node instance in a workitem handler?
                krisverlaenen

                John,

                 

                Your idea of just setting the ksession when creating the handler is indeed what we recommend (and also do ourselves in some handlers).  Note that this ksession is the same session as the one that creates the process instance, but the object that you retrieve (when using persistence) is actually a wrapper around the internal session.  That should however just delegate to the internal session.

                 

                Did you have any issues when setting the ksession like this, and if so, could you provide some more detail?

                 

                Thx,

                Kris

                • 5. Re: How to get current node instance in a workitem handler?
                  xmithj

                  Hi Kris

                   

                  Setting the ksession when creating the handler worked fine as long as I had a work item handler instance per request (i.e. different instances of the same handler are required to keep the ksession created per business process invocation). But then I faced problems when resuming a persisted business process: When an external event (like a userTask completion) reclaimed the persisted business process, it resumes the execution on a new work item handler instance that doesn’t know the original ksession. So I had to retrieved the persisted ksession from the DB inside the work item; but the retrieved one was not the same that the one that resumed the business process. I could have done something wrong at that time, but all the custom code could be avoided if you expose the ksession wrapped inside the WorkItemManager. Thus, work items handler would have access to the ksession that created them, and having the ksession means work items could access facts (objects) , globals, etc stored inside the ksession!

                   

                  Looking forward to hearing your thoughts.

                   

                  John

                  • 6. Re: How to get current node instance in a workitem handler?
                    affandar

                    I had to store the ksession id and the process instances it is running separately for recovery. On server restart, I load all sessions and for all process instances stored in my session->processinstanceid mapping table I call ksession.getProcessInstance(processinstanceid).

                     

                    From another thread here: https://community.jboss.org/thread/195459, it seems like it should be possible to load a process instance into a ksession different from the one it was created in (with some caveats) but I didn't go that route.

                     

                    Once the right ksession is loaded and available to the workitemhandler, finding the nodeId is straightfoward. E.g. something like this:

                     

                    private WorkItemNodeInstance getCurrentWorkItemNodeInstance(WorkItem workItem) {

                              RuleFlowProcessInstance processInst = (RuleFlowProcessInstance)this.ksession.getProcessInstance(workItem.getProcessInstanceId());

                              Collection<NodeInstance> nodeInstances = processInst.getNodeInstances();

                              for(NodeInstance nodeInst : nodeInstances) {

                                        if(nodeInst instanceof WorkItemNodeInstance) {

                                                  if(((WorkItemNodeInstance)nodeInst).getWorkItem().getId() == workItem.getId()) {

                                                  return ((WorkItemNodeInstance)nodeInst);

                                                  }

                                        }

                              }

                              return null;

                    }

                     

                    HTH

                    • 7. Re: How to get current node instance in a workitem handler?

                      Hi Kris,

                       

                      Thank you a lot for your suggestion but I found one problem:

                      The work item currently has access to the process instance id, so you could just retrieve the process instance from the session and find the node instance that references this work item. 

                      I don't understand how can I find node instance 'that references this work item'. I went through documentation and sources with no result: NodeInstance doesn't seem to have Work Item reference, createWorkItem in WorkItemNodeInstance also doens't give any hints on how corresponding Node can be found by WorkItem.

                      I'm very interested in this problem partially because I need to get use of proposed workaround in https://issues.jboss.org/browse/JBPM-3618

                      I would be very thankful if you can help

                      • 8. Re: How to get current node instance in a workitem handler?
                        krisverlaenen
                        • 9. Re: How to get current node instance in a workitem handler?

                          Hi,

                           

                          great thanks! this should help me a lot. (separate thanks for very prompt reply!)