cancel
Showing results for 
Search instead for 
Did you mean: 

Error waking up a receice task with a boundary timer event

danilo1
Champ in-the-making
Champ in-the-making
Hi,

In my process I have a Receive Task that wait for an external signal made by activiti rest api.
It works fine, but If I associate to that task a boundary timer to simulate a timeout:
- if the timer fires is ok calling the next task,
- if the signal arrives before the timeout an internal exception is raised.

the BPMN:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <signal id="MySignal" name="My Signal"></signal>
  <process id="checkSignalKey" name="Check signal" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <scriptTask id="startingTask" name="First Task" scriptFormat="groovy" activiti:autoStoreVariables="true">
      <script>println(   execution.getActivityId() )

import java.util.Date;
import org.activiti.engine.ActivitiException;


      try  {
         String pushedVar = (String) execution.getVariable("pushedVar");
         if(pushedVar == null)
            pushedVar="";
         System.out.println (   "process: " + execution.getProcessInstanceId()  + " activity : " +   execution.getCurrentActivityId()  + " -  time: " +  new Date().getTime()   + " -  pushedVar :" +  pushedVar    );
      }  catch ( ActivitiException e ) {
         e.printStackTrace();
      }

println(   execution.getActivityId() )</script>
    </scriptTask>
    <scriptTask id="lastTask" name="Last Task" scriptFormat="groovy" activiti:autoStoreVariables="true">
      <script>println(   execution.getActivityId() )

import java.util.Date;
import org.activiti.engine.ActivitiException;


         try  {
         String pushedVar = (String) execution.getVariable("pushedVar");
         if(pushedVar == null)
            pushedVar="";
         System.out.println (   "process: " + execution.getProcessInstanceId()  + " activity : " +   execution.getCurrentActivityId()  + " -  time: " +  new Date().getTime()   +  " -  pushedVar :" +  pushedVar    );
      }  catch ( ActivitiException e ) {
         e.printStackTrace();
      }

println(   execution.getActivityId() )</script>
    </scriptTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="startingTask"></sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="lastTask" targetRef="endevent1"></sequenceFlow>
    <receiveTask id="receivetask1" name="Receive Task"></receiveTask>
    <sequenceFlow id="flow14" sourceRef="startingTask" targetRef="receivetask1"></sequenceFlow>
    <sequenceFlow id="flow15" sourceRef="receivetask1" targetRef="lastTask"></sequenceFlow>
    <boundaryEvent id="boundarytimer1" name="Timer" attachedToRef="receivetask1" cancelActivity="true">
      <timerEventDefinition>
        <timeDuration>PT5S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <scriptTask id="anotherTask" name="Another Task" scriptFormat="groovy" activiti:autoStoreVariables="true">
      <script>println(   execution.getActivityId() )

import java.util.Date;
import org.activiti.engine.ActivitiException;


         try  {
         String pushedVar = (String) execution.getVariable("pushedVar");
         if(pushedVar == null)
            pushedVar="";
         System.out.println (   "process: " + execution.getProcessInstanceId()  + " activity : " +   execution.getCurrentActivityId()  + " -  time: " +  new Date().getTime()   +  " -  pushedVar :" +  pushedVar    );
      }  catch ( ActivitiException e ) {
         e.printStackTrace();
      }

println(   execution.getActivityId() )</script>
    </scriptTask>
    <sequenceFlow id="flow16" sourceRef="boundarytimer1" targetRef="anotherTask"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_checkSignalKey">
    <bpmndi:BPMNPlane bpmnElement="checkSignalKey" id="BPMNPlane_checkSignalKey">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="30.0" y="40.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="620.0" y="40.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="startingTask" id="BPMNShape_startingTask">
        <omgdc:Bounds height="55.0" width="105.0" x="100.0" y="30.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="lastTask" id="BPMNShape_lastTask">
        <omgdc:Bounds height="55.0" width="105.0" x="480.0" y="30.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="receivetask1" id="BPMNShape_receivetask1">
        <omgdc:Bounds height="55.0" width="105.0" x="280.0" y="120.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="boundarytimer1" id="BPMNShape_boundarytimer1">
        <omgdc:Bounds height="30.0" width="30.0" x="330.0" y="170.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="anotherTask" id="BPMNShape_anotherTask">
        <omgdc:Bounds height="61.0" width="151.0" x="470.0" y="270.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="65.0" y="57.0"></omgdi:waypoint>
        <omgdi:waypoint x="100.0" y="57.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="585.0" y="57.0"></omgdi:waypoint>
        <omgdi:waypoint x="620.0" y="57.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14">
        <omgdi:waypoint x="152.0" y="85.0"></omgdi:waypoint>
        <omgdi:waypoint x="332.0" y="120.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow16" id="BPMNEdge_flow16">
        <omgdi:waypoint x="345.0" y="200.0"></omgdi:waypoint>
        <omgdi:waypoint x="545.0" y="270.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">
        <omgdi:waypoint x="332.0" y="120.0"></omgdi:waypoint>
        <omgdi:waypoint x="532.0" y="85.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>




And the unit test code (the Thread.sleep is used unly to avoid that method ends before the activiti runned process. 😞

   @Test
   @Deployment(resources = "CheckSignal.bpmn")
   public void checkSignal() throws Exception {
      String processKey = "checkSignalKey";

      // start process
      String reply = startProcess(processKey, null);
      Map<String, Object> map = getJsonValues(reply);
      String idProcess = (String) map.get("id");

      sendSignal(idProcess, null);
      
      
      
      // get if instance exists
      long secs = 0;
      do {
         Thread.sleep(1000);
         if ( (secs ++ ) > 10 ){
            throw new Exception("Timeout test. ");
         }
      } while (processExists(idProcess));

      return;
   }

   @Test
   @Deployment(resources = "CheckSignal.bpmn")
   public void checkSignalEventWithVars() throws Exception {
      String processKey = "checkSignalKey";

      // start process
      List<ProcessVariable> vars = new ArrayList<ProcessVariable>();
      vars.add(new ProcessVariable("pushedVar", "[A simple string variable]", "string"));
      
      String reply = startProcess(processKey, vars);
      Map<String, Object> map = getJsonValues(reply);
      String idProcess = (String) map.get("id");
      
      long secs = 2;
      System.out.println( "wait for " + secs + " seconds" );
      Thread.sleep(secs * 1000);

      vars.clear();
      vars.add(new ProcessVariable("pushedVar", "[The simple string variable is modified]", "string"));
      sendSignalEvent(idProcess, "My Signal", vars);
      
      // get if instance exists
      secs = 0;
      do {
         Thread.sleep(1000);
         if ( (secs ++ ) > 10 ){
            throw new Exception("Timeout test. ");
         }
      } while (processExists(idProcess));

      return;
   }



Is it a normal error?
As workaround i could move the timer in another process that is started by the principal when needs and wake up the first but I don't like it.


Thanks.
9 REPLIES 9

danilo1
Champ in-the-making
Champ in-the-making
Seems that when the timer is attached to the receive task lose the capability of intercept the signal.

In fact if the signal is sent before the timeout, activiti raise the "internal error" and then calls however the "timeout task".

jbarrez
Star Contributor
Star Contributor
That sounds like a bug. Which exception do you get?

danilo1
Champ in-the-making
Champ in-the-making
I am using rest-api and the returned message (after the http call)  is : {"errorMessage":"Internal Server Error","statusCode":500}.
The I am working with the original rest-api.war (5.13) and I do not know how I can produce a more verbose log. The modification of  the log4j.properties have do not  made any effect.

danilo1
Champ in-the-making
Champ in-the-making
Update:
I have investigated about the problem, so I got the sources, put a a try/catch in ExecutionActionRequest ( called by rest-api ) and then recompiled the activiti-rest package.

The outcome exception is a NullPointerException raised in the ExecutionEntity.signal(String signalName, Object signalData) method : the activiti attribute is set to null.

The modified ExecutionActionRequest rows (version 5.13)
<code>
  @Put
  public ExecutionResponse performExecutionAction(ExecutionActionRequest actionRequest) {
    if(!authenticate()) {
      return null;
    }
   
    Execution execution = getExecutionFromRequest();
   
    if(ExecutionActionRequest.ACTION_SIGNAL.equals(actionRequest.getAction())) {
try{ //<————— ADDED BY ME
        ActivitiUtil.getRuntimeService().signal(execution.getId());
}catch (Throwable e){ //<————— ADDED BY ME
  if( execution == null  )  //<————— ADDED BY ME
   System.out.println( "execution ==null" ); //<————— ADDED BY ME
  e.printStackTrace(); //<————— ADDED BY ME
} //<————— ADDED BY ME
    } else if(ExecutionActionRequest.ACTION_SIGNAL_EVENT_RECEIVED.equals(actionRequest.getAction())) {
……………
</code>

And the outcome stack trace
<code>
java.lang.NullPointerException
org.activiti.engine.impl.persistence.entity.ExecutionEntity.signal(ExecutionEntity.java:348)
org.activiti.engine.impl.cmd.SignalCmd.execute(SignalCmd.java:45)
org.activiti.engine.impl.cmd.NeedsActiveExecutionCmd.execute(NeedsActiveExecutionCmd.java:55)
org.activiti.engine.impl.interceptor.CommandExecutorImpl.execute(CommandExecutorImpl.java:24)
org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:61)
org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:42)
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:40)
org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:37)
org.activiti.engine.impl.RuntimeServiceImpl.signal(RuntimeServiceImpl.java:184)
org.activiti.rest.api.runtime.process.ExecutionResource.performExecutionAction(ExecutionResource.java:50)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.restlet.resource.ServerResource.doHandle(ServerResource.java:449)
org.restlet.resource.ServerResource.put(ServerResource.java:1173)
org.restlet.resource.ServerResource.doHandle(ServerResource.java:524)
org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:590)
org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:302)
org.restlet.resource.ServerResource.handle(ServerResource.java:849)
org.restlet.resource.Finder.handle(Finder.java:513)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Router.doHandle(Router.java:500)
org.restlet.routing.Router.handle(Router.java:740)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:155)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.engine.ChainHelper.handle(ChainHelper.java:114)
org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:75)
org.restlet.Application.handle(Application.java:391)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Router.doHandle(Router.java:500)
org.restlet.routing.Router.handle(Router.java:740)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.routing.Router.doHandle(Router.java:500)
org.restlet.routing.Router.handle(Router.java:740)
org.restlet.routing.Filter.doHandle(Filter.java:159)
org.restlet.routing.Filter.handle(Filter.java:206)
org.restlet.engine.ChainHelper.handle(ChainHelper.java:114)
org.restlet.Component.handle(Component.java:391)
org.restlet.Server.handle(Server.java:491)
org.restlet.engine.ServerHelper.handle(ServerHelper.java:74)
org.restlet.engine.http.HttpServerHelper.handle(HttpServerHelper.java:153)
org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1031)
javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:165)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:372)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:679)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:931)
java.lang.Thread.run(Thread.java:662)
</code>

chkal
Champ in-the-making
Champ in-the-making
Any news on this one? I'm running into the same issue in 5.13.1. So basically sending a signal to the execution fails with a NPE as described above. But only if a boundary timer is attached to the receive task.

frederikherema1
Star Contributor
Star Contributor
In case a boundary-event is attached to the receive-task, an additional execution is created under the hood (add scoping is needed for the boundary-event). So you should make sure you signal that child-execution, instead of the parent (== the execution you whould normally use to signal if no boundary is attached).

Can you try the proposed solution and come back if this is not the solution?

chkal
Champ in-the-making
Champ in-the-making
Thanks a lot for your response. You are absolutely right. I was sending the signal to the wrong execution which resulted in the NPE mentioned above.

Basically I was doing something like this:

<java>
Execution execution = runtimeService.createExecutionQuery()
  .processInstanceBusinessKey( "foobar" )
  .singleResult();

runtimeService.signal( execution.getId() );
</java>

I've changed it to something like this and now it works fine:

<java>
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
  .processInstanceBusinessKey( "foobar" )
  .singleResult();

Execution execution = runtimeService.createExecutionQuery()
  .processInstanceId( processInstance.getId() )
  .activityId( "receiveActivityId" )
  .singleResult();

runtimeService.signal( execution.getId() );
</java>

Thanks a lot for your help.

jaikumar
Champ in-the-making
Champ in-the-making
Hi,

I have used receive task with timer boundary event, bu timer boundary event fires continuously, its not wait until the duration ends. In timer event I have set value as PT10M for repeated every 10 minutes it should fire. But firing continuously.

trademak
Star Contributor
Star Contributor
Hi,

Could you provide a unit test showing your issue and create a JIRA issue with it?

Thanks,
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.