cancel
Showing results for 
Search instead for 
Did you mean: 

Java Service Task custom asynchronous behaviour: Complete task using signal or callback.

saraiva
Champ in-the-making
Champ in-the-making
Hello, this has already been answered but the solutions have not been working out for me.

Activiti asynchronous behaviour is fairly simple and only allows the user to enable a flag which tells activiti engine to insert such task in a execution queue (managing a pool of threads).

What i want is not to insert my java service task in a pool but to passivate its behaviour and only complete such task when an external signal is received and/or a callback is called.

My attempt:

    class customAsyncTask extends TaskActivityBehavior {
      override def execute(execution: ActivityExecution): Unit = {
        val future = Future {
          println(s"Executing customAsyncTask -> ${execution.getCurrentActivityName}, ${cur}")
        }

        future.onComplete {
          case Success(result) => leave(execution)
          case _ => // whatever
        }
     }
      def signal(processInstanceId : String, transition : String) = {
        val commandExecutor  = main.processEngine.getProcessEngineConfiguration.asInstanceOf[ProcessEngineConfigurationImpl].getCommandExecutor
        val command = new customSignal(processInstanceId, transition)
        commandExecutor.execute(command)
      }
 
    }

On my previous code sample i have registered a scala future callback which when called will terminate the current activity and move to the next.

I also have a signal method which builds a custom signal that based on the processId and a name will call execution.take with the appropriate transition.


On both cases i am getting the following error (the bottom stack changes a little):


    java.lang.NullPointerException
   at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:636)
   at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:629)
   at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:453)
   at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:431)
   at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performOutgoingBehavior(BpmnActivityBehavior.java:140)
   at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performDefaultOutgoingBehavior(BpmnActivityBehavior.java:66)
   at org.activiti.engine.impl.bpmn.behavior.FlowNodeActivityBehavior.leave(FlowNodeActivityBehavior.java:44)
   at org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior.leave(AbstractBpmnActivityBehavior.java:47)


Unfortunately, it is highly likely that the engine is erasing the information concerning the execution when the execute method returns, even though no complete/leave/take has been called. Even though my callback has the execution object in context, when i query for information using its proccess ID all i receive is null.

So, what i am doing wrong here? How can i achieve the behaviour that i want?
3 REPLIES 3

saraiva
Champ in-the-making
Champ in-the-making
To further clarify my issue. I attempted to signal the runTimeService directly in the callback:

<code>
    processEngine.getRuntimeService().signal(execution.getId());
</code>

However, as i previously said, the engine no longer holds my process.

<code>

org.activiti.engine.ActivitiObjectNotFoundException: execution 4160010 doesn't exist
at org.activiti.engine.impl.cmd.NeedsActiveExecutionCmd.execute(NeedsActiveExecutionCmd.java:48)
at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:24)
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:57)
at org.activiti.engine.impl.interceptor.JtaTransactionInterceptor.execute(JtaTransactionInterceptor.java:65)
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:37)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:40)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:35)
at org.activiti.engine.impl.RuntimeServiceImpl.signal(RuntimeServiceImpl.java:278)
at pt.ptinovacao.na.swe.testcase.bpm.base.tests.activiti.test.customAsyncTask$$anonfun$execute$1.apply(custom.scala:83)
at pt.ptinovacao.na.swe.testcase.bpm.base.tests.activiti.test.customAsyncTask$$anonfun$execute$1.apply(custom.scala:75)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

</code>

saraiva
Champ in-the-making
Champ in-the-making
And to further clarify this is where returning null both using runTimeManager directly or a customSignal

<code>
val execution = commandContext.getExecutionEntityManager.findExecutionById(executionID)
</code>

jbarrez
Star Contributor
Star Contributor
Really hard to say what you're trying to do here … any chance you can wrap it up it in a unit test.

But from what i'm seeing, is that you do a leave() in the execute()? You can't use leave() if you later expect a signal() to be executed. If you want to do wait behaviour, you need to remove the leave().