Using Asynchronous Service Invocation but the service does not give the expected result

Hi,
I am using an Asynchronous service invocation to generating war file. I use here a simple service task that implement Timer till 5, the problem is the service does not give the result(timer) when I deploy war file to tomcat but when I test it by JUnit test it gives the expected result. I followed this example camunda-bpm-examples/servicetask/service-invocation-asynchronous at master · camunda/camunda-bpm-examples · GitHub

I also put my code in the bitbucket
https://bitbucket.org/Ali_Al-Hashimi/asysncserviceinvocation/src/76f7070e346f?at=master

lastSEQ.bpmn (4.3 KB)
processes.xml (493 Bytes)
camunda.cfg.xml (398 Bytes)
}pom.xml (3.5 KB)

         AsysncInvocationApp1.java   src/main/java

package org.camunda.asysncinvocation;

import org.camunda.bpm.application.ProcessApplication;
import org.camunda.bpm.application.impl.ServletProcessApplication;

@ProcessApplication("Asynchronous1 App")
public class AsysncInvocationApp1 extends ServletProcessApplication {
  // empty implementation

}
package org.camunda.quickstart.servicetask.invocation;

import java.util.HashMap;
import java.util.Map;

import org.camunda.bpm.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution;
import org.camunda.bpm.engine.impl.pvm.delegate.SignallableActivityBehavior;
import org.camunda.quickstart.servicetask.invocation.MockMessageQueue.Message;


public class AsynchronousServiceTask extends AbstractBpmnActivityBehavior {

  public static final String EXECUTION_ID = "executionId";
  
	public void execute(final ActivityExecution execution) throws Exception {
	  
	  // Build the payload for the message: 
	  Map<String, Object> payload = new HashMap<String, Object>(execution.getVariables());
	  
	  // Add the execution id to the payload:
	  payload.put(EXECUTION_ID, execution.getId());
	  
	  // Publish a message to the outbound message queue. This method returns after the message has 
	  // been put into the queue. The actual service implementation (Business Logic) will not yet 
	  // be invoked:
	  MockMessageQueue.INSTANCE.send(new Message(payload));
	  //System.out.println("Ckecking Message from AsysnchronousServiceTask Class");
	  
	}
			
	public void signal(ActivityExecution execution, String signalName, Object signalData) throws Exception {
	  
	//receive the response  
		Map<String, Object> payload1 = new HashMap<String, Object>(execution.getVariables());
		
		for (Map.Entry<String, Object>mm : payload1.entrySet()){
			String key = mm.getKey();
			Object value = mm.getValue();
			System.out.println(key + " " + value );
		}
		
	// leave the service task activity:	
	  leave(execution);
	  

	  
	  
	}

}

    BusinessLogic.java   src/main/java
package org.camunda.quickstart.servicetask.invocation;


import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.quickstart.servicetask.invocation.MockMessageQueue.Message;


public class BusinessLogic {
  
  //public static final String SHOULD_FAIL_VAR_NAME = "shouldFail";
	
	
	   // putting the text in variables
  public static final String Msg = "timer completed with seconds =";
  public static final int Times = 5;
 
  
  public static BusinessLogic INSTANCE = new BusinessLogic();
    
  public void invoke(Message message, ProcessEngine processEngine) throws InterruptedException {    
	  
	   
	  TimeUnit.SECONDS.sleep(5);
    // Process the message and send a callback.
    
    // Extract values from payload:     
    Map<String, Object> requestPayload = message.getPayload();
    // the execution id is used as correlation identifier 
    String executionId = (String) requestPayload.get(AsynchronousServiceTask.EXECUTION_ID);    

    // putting the   variables contained the text in Callback Payload
     Map<String, Object> callbackPayload = Collections.<String,Object>singletonMap(Msg, Times);
      processEngine.getRuntimeService().signal(executionId, callbackPayload);
  
   // }
  }

}
  MockMessageQueue.java           src/main/java 
package org.camunda.quickstart.servicetask.invocation;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * <p>This class is supposed to mock the queuing infrastructure between the process engine 
 * and the service implementation. In a real life scenario, we would use reliable queuing 
 * middleware such as a transactional messaging system (typically JMS).</p>
 *
 */
public class MockMessageQueue {
  
  /** a Message with payload */
  public static class Message {
    
    protected Map<String, Object> payload = new HashMap<String, Object>();

    public Message(Map<String, Object> payload) {
      this.payload = payload;
    }
    
    public Map<String, Object> getPayload() {
      return payload;
    }
     
  }
  
  protected List<Message> queue = new LinkedList<MockMessageQueue.Message>();
  
  public final static MockMessageQueue INSTANCE = new MockMessageQueue();
  
  public void send(Message m) {
    queue.add(m);
  }
  
  public Message getNextMessage() {
    return queue.remove(0);
  }

}
  TestAsynchronousServiceTask.java    src/test/java
package org.camunda.quickstart.servicetask.invocation.sync;

import static org.junit.Assert.*;

import org.junit.Test;




import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.test.Deployment;
import org.camunda.bpm.engine.test.ProcessEngineRule;
import org.camunda.quickstart.servicetask.invocation.AsynchronousServiceTask;
import org.camunda.quickstart.servicetask.invocation.BusinessLogic;
import org.camunda.quickstart.servicetask.invocation.MockMessageQueue;
import org.camunda.quickstart.servicetask.invocation.MockMessageQueue.Message;
import org.junit.Rule;

/**
 * Test case for demonstrating the asynchronous service invocation.
 * 
 */
public class TestAsynchronousServiceTask {

  @Rule
  public ProcessEngineRule processEngineRule = new ProcessEngineRule();

  @Test
  @Deployment(resources = { "lastSEQ.bpmn" })
  public void testServiceInvocationSuccessful() throws InterruptedException {

    final ProcessEngine processEngine = processEngineRule.getProcessEngine();
    final RuntimeService runtimeService = processEngineRule.getRuntimeService();
    final TaskService taskService = processEngineRule.getTaskService();

    // this invocation should NOT fail
    Map<String, Object> variables = Collections.<String, Object> singletonMap(BusinessLogic.Msg, false);

    // start the process instance
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("asynInvocc1", variables);

    // the process instance is now waiting in the first wait state (user task):
    Task userTask_1 = taskService.createTaskQuery()
      .taskDefinitionKey("userTask_1")
      .processInstanceId(processInstance.getId())
      .singleResult();
    assertNotNull(userTask_1);

    // Complete the first task. This triggers causes the Service task to be executed. 
    // After the method call returns, the message will be put into the queue and 
    // the process instance is waiting in the service task activity.
    taskService.complete(userTask_1.getId());

    // the process instance is now waiting in the service task activity:
    assertEquals(Arrays.asList("AsyncServiceTask"), runtimeService.getActiveActivityIds(processInstance.getId()));
    
    // the message is present in the Queue:
    Message message = MockMessageQueue.INSTANCE.getNextMessage();
    assertNotNull(message);
    assertEquals(processInstance.getId(), message.getPayload().get(AsynchronousServiceTask.EXECUTION_ID));

    // Next, trigger the business logic. This will send the callback to the process engine.
    // When this method call returns, the process instance will be waiting in the next waitstate.
    BusinessLogic.INSTANCE.invoke(message, processEngine);
    
    // the process instance is now waiting in the second wait state (user task):
    Task userTask_2 = taskService.createTaskQuery()
      .taskDefinitionKey("userTask_2")
      .processInstanceId(processInstance.getId())
      .singleResult();
    assertNotNull(userTask_2);
        
    // check for variable set by the service task:
    variables = runtimeService.getVariables(processInstance.getId());
    assertEquals(BusinessLogic.Times, variables.get(BusinessLogic.Msg));

  }

  @Test
  @Deployment(resources = { "lastSEQ.bpmn" })
  public void testServiceInvocationFailure() {

    final ProcessEngine processEngine = processEngineRule.getProcessEngine();
    final RuntimeService runtimeService = processEngine.getRuntimeService();
    final TaskService taskService = processEngine.getTaskService();

    // this invocation should fail
    Map<String, Object> variables = Collections.<String, Object> singletonMap(BusinessLogic.Msg, true);

    // start the process instance
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("asynInvocc1", variables);

    // the process instance is now waiting in the first wait state (user task):
    Task userTask_1 = taskService.createTaskQuery()
      .taskDefinitionKey("userTask_1")
      .processInstanceId(processInstance.getId())
      .singleResult();
    assertNotNull(userTask_1);

    // Complete the first task. This triggers causes the Service task to be executed. 
    // After the method call returns, the message will be put into the queue and 
    // the process instance is waiting in the service task activity.
    taskService.complete(userTask_1.getId());

    // the process instance is now waiting in the service task activity:
    assertEquals(Arrays.asList("AsyncServiceTask"), runtimeService.getActiveActivityIds(processInstance.getId()));
    
    // the message is present in the Queue:
    Message message = MockMessageQueue.INSTANCE.getNextMessage();
    assertNotNull(message);
    assertEquals(processInstance.getId(), message.getPayload().get(AsynchronousServiceTask.EXECUTION_ID));


    // the process instance is still waiting in the service task activity:
    assertEquals(Arrays.asList("AsyncServiceTask"), runtimeService.getActiveActivityIds(processInstance.getId()));

  }

Hi,

Please put the description of your problem into the body of the post, not the title. Please format code your code blocks properly (see how this can be done with Markdown here).

Cheers,
Thorben

Hi @thorben,

Thanks for your notes, I made the require changes and uploaded the code to the bitbucket.

Best Regards,

Hi @AlioPro,

Do you have any code that calls BusinessLogic#invoke in the case where you deploy the application to Tomcat?

Also note that MockMessageQueue is meant for unit testing purposes, since it is not an active component that triggers a message receiver. In practice, you would rather use a real message queue that your business logic subscribes to (see also the class comment of MockMessageQueue).

Cheers,
Thorben

Hi @thorben,

Actually no, I did not called BusinessLogic#invoke. what I did for this class just changed the variables names & values, add a timer and left other code as it is in the example on GitHub.

Also instead of MockMessageQueue I would start reading “asynchronous-messaging-jms”

Best Regards,

Hi @AlioPro,

Can you then please share the code that you actually run on Tomcat?

Cheers,
Thorben

Hi @thorben

yes off course the code in
https://bitbucket.org/Ali_Al-Hashimi/asysncserviceinvocation/src/76f7070e346f2686ad039e7dbc2fb88056baa0d2?at=master

For the code, I use pom.xml to generate war file ,and the war file I deploy it to the Tomcat

Hi @AlioPro,

I think I am misunderstanding something here. If you do not call BusinessLogic#invoke yourself, then noone calls this method. Is your question now why it does not get executed?

Sorry, I’m having trouble understanding the question. Perhaps you can rephrase it.

Cheers,
Thorben

Hi @thorben,

I am sorry for the misunderstanding, That’s right I did not call BusinessLogic#invoke and in the JUnit, it’s work fine since JUnit class contains BusinessLogic#invoke, But I am not sure where should I call BusinessLogic#invoke.