7 Replies Latest reply on Feb 25, 2006 12:16 PM by kukeltje

    Task assignment handler not being called second time through

    iterrell

      I have a process with a task in a loop, and although the assignment handler gets called the first time, it doesn't get called any subsequent times. Here's an example process that shows the behavior:

      <process-definition name="Task Loop Test">
       <swimlane name='sl'>
       <assignment class='com.gallium.sandbox.delegation.TaskAssignmentHandler' />
       </swimlane>
       <start-state name="start">
       <transition name="go" to="mytask" />
       </start-state>
       <task-node name="mytask">
       <task name='myTask' swimlane='sl' />
       <transition name="again" to="wait" />
       <transition name="done" to="end" />
       </task-node>
       <state name="wait">
       <timer duedate="20 seconds" transition="continue" />
       <transition name="continue" to="mytask" />
       </state>
       <end-state name="end"/>
      </process-definition>
      


      Here's my assignment handler:

       public void assign(Assignable ass, ExecutionContext ctx) throws Exception {
       log.debug("****************");
       log.debug("Assigning to Ian");
       log.debug("****************");
       ass.setActorId("ian");
       }
      


      Here's my log for leaving the start state:

      2006-02-23 09:58:42,375 DEBUG [org.jbpm.configuration.JbpmContextInfo] creating jbpm context with service factories '[message, scheduler, logging, persistence, authentication]'
      2006-02-23 09:58:42,375 DEBUG [org.jbpm.JbpmContext] creating JbpmContext
      2006-02-23 09:58:42,375 DEBUG [org.jbpm.persistence.db.DbPersistenceServiceFactory] creating persistence service
      2006-02-23 09:58:42,375 DEBUG [org.jbpm.persistence.db.DbPersistenceService] creating hibernate session
      2006-02-23 09:58:42,375 DEBUG [org.jbpm.persistence.db.DbPersistenceService] beginning hibernate transaction
      2006-02-23 09:58:42,406 DEBUG [org.jbpm.graph.def.GraphElement] event 'before-signal' on 'StartState(start)' for 'Token(/)'
      2006-02-23 09:58:42,421 WARN [org.hibernate.engine.StatefulPersistenceContext] Narrowing proxy to class org.jbpm.graph.node.StartState - this operation breaks ==
      2006-02-23 09:58:42,421 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-leave' on 'StartState(start)' for 'Token(/)'
      2006-02-23 09:58:42,421 DEBUG [org.jbpm.graph.def.GraphElement] event 'transition' on 'Transition(go)' for 'Token(/)'
      2006-02-23 09:58:42,421 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-enter' on 'TaskNode(mytask)' for 'Token(/)'
      2006-02-23 09:58:42,421 WARN [org.hibernate.engine.StatefulPersistenceContext] Narrowing proxy to class org.jbpm.graph.node.TaskNode - this operation breaks ==
      2006-02-23 09:58:42,921 DEBUG [org.jbpm.graph.def.GraphElement] event 'task-create' on 'Task(myTask)' for 'Token(/)'
      2006-02-23 09:58:42,953 DEBUG [long] ****************
      2006-02-23 09:58:42,953 DEBUG [long] Assigning to Ian
      2006-02-23 09:58:42,953 DEBUG [long] ****************
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.graph.def.GraphElement] event 'task-assign' on 'Task(myTask)' for 'Token(/)'
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.graph.def.GraphElement] event 'after-signal' on 'StartState(start)' for 'Token(/)'
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.svc.Services] executing default save operations
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.svc.save.HibernateSaveOperation] saving process instance
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.svc.save.SaveLogsOperation] flushing logs to logging service.
      2006-02-23 09:58:42,953 DEBUG [org.jbpm.svc.save.CascadeSaveOperation] cascading save of 'org.jbpm.graph.exe.ProcessInstance@1ba3afe'
      2006-02-23 09:58:42,984 DEBUG [org.jbpm.JbpmContext] closing JbpmContext
      2006-02-23 09:58:42,984 DEBUG [org.jbpm.svc.Services] closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@14cf1b9
      2006-02-23 09:58:42,984 DEBUG [org.jbpm.persistence.db.DbPersistenceService] committing hibernate transaction
      2006-02-23 09:58:43,171 DEBUG [org.jbpm.persistence.db.DbPersistenceService] closing hibernate session
      2006-02-23 09:58:43,187 DEBUG [org.jbpm.svc.Services] closing service 'logging': org.jbpm.logging.db.DbLoggingService@1c33b55
      


      It enters the task node and correctly calls the swimlane's assignment handler.

      Here I end the task with a transition to "wait:"

      2006-02-23 09:59:08,656 DEBUG [org.jbpm.configuration.JbpmContextInfo] creating jbpm context with service factories '[message, scheduler, logging, persistence, authentication]'
      2006-02-23 09:59:08,656 DEBUG [org.jbpm.JbpmContext] creating JbpmContext
      2006-02-23 09:59:08,656 DEBUG [org.jbpm.persistence.db.DbPersistenceServiceFactory] creating persistence service
      2006-02-23 09:59:08,656 DEBUG [org.jbpm.persistence.db.DbPersistenceService] creating hibernate session
      2006-02-23 09:59:08,656 DEBUG [org.jbpm.persistence.db.DbPersistenceService] beginning hibernate transaction
      2006-02-23 09:59:08,781 DEBUG [org.jbpm.graph.def.GraphElement] event 'task-end' on 'Task(myTask)' for 'Token(/)'
      2006-02-23 09:59:08,796 DEBUG [org.jbpm.taskmgmt.exe.TaskInstance] completion of task 'myTask' results in taking transition 'Transition(again)'
      2006-02-23 09:59:08,796 DEBUG [org.jbpm.graph.def.GraphElement] event 'before-signal' on 'TaskNode(mytask)' for 'Token(/)'
      2006-02-23 09:59:08,796 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-leave' on 'TaskNode(mytask)' for 'Token(/)'
      2006-02-23 09:59:08,796 DEBUG [org.jbpm.graph.def.GraphElement] event 'transition' on 'Transition(again)' for 'Token(/)'
      2006-02-23 09:59:08,812 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-enter' on 'State(wait)' for 'Token(/)'
      2006-02-23 09:59:08,812 WARN [org.hibernate.engine.StatefulPersistenceContext] Narrowing proxy to class org.jbpm.graph.node.State - this operation breaks ==
      2006-02-23 09:59:08,875 DEBUG [org.jbpm.graph.def.GraphElement] executing action 'CreateTimerAction(130cda4)'
      2006-02-23 09:59:08,875 DEBUG [org.jbpm.graph.def.GraphElement] event 'timer-create' on 'State(wait)' for 'Token(/)'
      2006-02-23 09:59:08,890 DEBUG [org.jbpm.graph.def.GraphElement] event 'after-signal' on 'TaskNode(mytask)' for 'Token(/)'
      2006-02-23 09:59:08,890 DEBUG [org.jbpm.svc.Services] executing default save operations
      2006-02-23 09:59:08,890 DEBUG [org.jbpm.svc.save.HibernateSaveOperation] saving process instance
      2006-02-23 09:59:08,890 DEBUG [org.jbpm.svc.save.SaveLogsOperation] flushing logs to logging service.
      2006-02-23 09:59:08,890 DEBUG [org.jbpm.svc.save.CascadeSaveOperation] cascading save of 'org.jbpm.graph.exe.ProcessInstance@5e60f2'
      2006-02-23 09:59:08,921 DEBUG [org.jbpm.JbpmContext] closing JbpmContext
      2006-02-23 09:59:08,921 DEBUG [org.jbpm.svc.Services] closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@2720f6
      2006-02-23 09:59:08,921 DEBUG [org.jbpm.persistence.db.DbPersistenceService] committing hibernate transaction
      2006-02-23 09:59:08,984 DEBUG [org.jbpm.persistence.db.DbPersistenceService] closing hibernate session
      2006-02-23 09:59:08,984 DEBUG [org.jbpm.svc.Services] closing service 'scheduler': org.jbpm.scheduler.db.DbSchedulerService@5353c8
      2006-02-23 09:59:08,984 DEBUG [org.jbpm.svc.Services] closing service 'logging': org.jbpm.logging.db.DbLoggingService@a19cc5
      


      Here's a clip to show that it was saved properly and the scheduler finds the timer:

      2006-02-23 09:59:11,234 DEBUG [org.jbpm.configuration.JbpmContextInfo] creating jbpm context with service factories '[message, scheduler, logging, persistence, authentication]'
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.JbpmContext] creating JbpmContext
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.persistence.db.DbPersistenceServiceFactory] creating persistence service
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.persistence.db.DbPersistenceService] creating hibernate session
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.persistence.db.DbPersistenceService] beginning hibernate transaction
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] checking for timers
      2006-02-23 09:59:11,328 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] found timer timer(wait,09:59:28,000)
      2006-02-23 09:59:11,406 DEBUG [org.jbpm.JbpmContext] closing JbpmContext
      2006-02-23 09:59:11,406 DEBUG [org.jbpm.svc.Services] closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@10df8c7
      2006-02-23 09:59:11,406 DEBUG [org.jbpm.persistence.db.DbPersistenceService] committing hibernate transaction
      2006-02-23 09:59:11,406 DEBUG [org.jbpm.persistence.db.DbPersistenceService] closing hibernate session
      


      And here's the execution of the timer:
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.configuration.JbpmContextInfo] creating jbpm context with service factories '[message, scheduler, logging, persistence, authentication]'
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.JbpmContext] creating JbpmContext
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.persistence.db.DbPersistenceServiceFactory] creating persistence service
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.persistence.db.DbPersistenceService] creating hibernate session
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.persistence.db.DbPersistenceService] beginning hibernate transaction
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] checking for timers
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] found timer timer(wait,09:59:28,000)
      2006-02-23 09:59:28,000 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] executing timer 'timer(wait,09:59:28,000)'
      2006-02-23 09:59:28,015 DEBUG [org.jbpm.graph.def.GraphElement] event 'before-signal' on 'State(wait)' for 'Token(/)'
      2006-02-23 09:59:28,015 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-leave' on 'State(wait)' for 'Token(/)'
      2006-02-23 09:59:28,109 DEBUG [org.jbpm.graph.def.GraphElement] executing action 'CancelTimerAction(8d2e37)'
      2006-02-23 09:59:28,109 DEBUG [org.jbpm.graph.def.GraphElement] event 'transition' on 'Transition(continue)' for 'Token(/)'
      2006-02-23 09:59:28,109 DEBUG [org.jbpm.graph.def.GraphElement] event 'node-enter' on 'TaskNode(mytask)' for 'Token(/)'
      2006-02-23 09:59:28,109 WARN [org.hibernate.engine.StatefulPersistenceContext] Narrowing proxy to class org.jbpm.graph.node.TaskNode - this operation breaks ==
      2006-02-23 09:59:28,109 DEBUG [org.jbpm.graph.def.GraphElement] event 'task-create' on 'Task(myTask)' for 'Token(/)'
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.graph.def.GraphElement] event 'task-assign' on 'Task(myTask)' for 'Token(/)'
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.graph.def.GraphElement] event 'after-signal' on 'State(wait)' for 'Token(/)'
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.svc.Services] executing default save operations
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.svc.save.HibernateSaveOperation] saving process instance
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.svc.save.SaveLogsOperation] flushing logs to logging service.
      2006-02-23 09:59:28,203 DEBUG [org.jbpm.svc.save.CascadeSaveOperation] cascading save of 'org.jbpm.graph.exe.ProcessInstance@ffce21'
      2006-02-23 09:59:28,234 DEBUG [org.jbpm.scheduler.impl.SchedulerThread] deleting timer 'timer(wait,09:59:28,000)'
      2006-02-23 09:59:28,234 DEBUG [org.jbpm.JbpmContext] closing JbpmContext
      2006-02-23 09:59:28,234 DEBUG [org.jbpm.svc.Services] closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@1246bec
      2006-02-23 09:59:28,234 DEBUG [org.jbpm.persistence.db.DbPersistenceService] committing hibernate transaction
      2006-02-23 09:59:28,296 DEBUG [org.jbpm.persistence.db.DbPersistenceService] closing hibernate session
      2006-02-23 09:59:28,296 DEBUG [org.jbpm.svc.Services] closing service 'scheduler': org.jbpm.scheduler.db.DbSchedulerService@1acc826
      2006-02-23 09:59:28,296 DEBUG [org.jbpm.svc.Services] closing service 'logging': org.jbpm.logging.db.DbLoggingService@8843f5
      


      It fires the task-assign event, it just doesn't call my custom code. Any ideas what's going on here, or any workaround? This is a critical part of my application, and all help is appreciated.

      Thanks in advance,
      Ian

        • 1. Re: Task assignment handler not being called second time thr
          kukeltje

          afaik, jBPM does not call the assignmenthandler again if the swimlane already has an actor assigned in a swimlane. This is at least what I saw too in jBPM 3.0 and are trying to verify that now by looking in the code. What version are you using?

          • 2. Re: Task assignment handler not being called second time thr
            iterrell

            I'm using 3.1.

            It strikes me that if an action is used for task assignment, it should call the action every time. What if a process instance runs for a long time (mine will run for at least 3 or 4 months) and the task actors should be set based on information that could be modified by the application?

            Ian

            • 3. Re: Task assignment handler not being called second time thr
              kukeltje

              in org.jbpm.taskmgmt.exe.TaskMgmtInstance the following code is present.

              public SwimlaneInstance getInitializedSwimlaneInstance(ExecutionContext executionContext, Swimlane swimlane) {
               // initialize the swimlane
               if (swimlaneInstances==null) swimlaneInstances = new HashMap();
               SwimlaneInstance swimlaneInstance = (SwimlaneInstance) swimlaneInstances.get(swimlane.getName());
               if (swimlaneInstance==null) {
               swimlaneInstance = new SwimlaneInstance(swimlane);
               addSwimlaneInstance(swimlaneInstance);
               // assign the swimlaneInstance
               invokeAssignmentHandler(swimlane.getAssignmentDelegation(), swimlaneInstance, executionContext);
               }
              


              So this means that if there is an initialized swimlane for a taskinstance, the assignmenthandler will not be called again. This wil not happen if you put the assignmenthandler directly on the task, not via a swimlane. Not sure if this is realy a bug, as designed or just an overlooked issue.

              • 4. Re: Task assignment handler not being called second time thr
                iterrell

                Thanks for the information and the workaround.

                I think it's unintuitive behavior at best.

                Ian

                • 5. Re: Task assignment handler not being called second time thr
                  kukeltje

                  I agree. It should either be changed or the current behaviour should be added to the docs.

                  I could do either. There is already a jira issue where I mentioned this but no real response (including from me ;-) ) on what to do. I'll see what I should do

                  Ronald

                  • 6. Re: Task assignment handler not being called second time thr
                    icyjamie

                    The contract of the swimlane is clear afaik:
                    "A swimlane is a process role. It is a mechanism to specify that multiple tasks in the process should be done by the same actor. So after the first task instance is created for a given swimlane, the actor should be remembered in the process for all subsequent tasks that are in the same swimlane. A swimlane therefore has one assignment and all tasks that reference a swimlane should not specify an assignment.

                    When the first task in a given swimlane is created, the AssignmentHandler of the swimlane is called. The Assignable that is passed to the AssignmentHandler will be the SwimlaneInstance. Important to know is that all assignments that are done on the task instances in a given swimlane will propagate to the swimlane instance. This behaviour is implemented as the default because the person that takes a task to fulfilling a certain process role will have the knowledge of that perticular process. So all subsequent assignements of task instances to that swimlane are done automatically to that user. "

                    The swimlane assignment handler is there to initialize the swimlane beforehand. That is what is designed for. The taskinstance assignment handler works directly on the task, to assign something.
                    If you need other behaviour, you can implement a process scoped task-create event, that sets the assignment as well, and forget about the swimlane.

                    • 7. Re: Task assignment handler not being called second time thr
                      kukeltje

                      All good and realy valid arguments.

                      This behaviour is implemented as the default because the person that takes a task to fulfilling a certain process role will have the knowledge of that perticular process. So all subsequent assignements of task instances to that swimlane are done automatically to that user.


                      It's true that swimlanes are roles, but in most systems we have to develop for our customers it is not so that a task in the same swimlane of a processinstance should be acted upon by the same person. It often depends on availability etc. I know there is a workaround by adding specific assignments to the tasks and that works, but now we can not easily select which tasks are for which role. Another solutuion is to add an task-enter event and if needed change the actor in the swimlane. This way I have some part of the code in the swimlane assignment handler and some in the normal assignment handler. With some java features, it can be based on the same code but it just does not feel right.

                      Adding a boolean e.g. to the assignmenthandler like 'reval=true/false' (re-evaluate) and checking this if the swimlanceinstance is checked for not being null could provide a solution as would adding an attribute to the swimlane definition in jpdl.

                      otoh, the first solution (using an event on entering) a task is more explicit. I think I go for this solution if I can report back who the task is assigned to like now in the demo.

                      Ronald