How to use triggerable

Hi, I want to use serviceTask with triggerable and async.But I don’t know how to use it, can anybody give me an example?

I’m confused:

  1. Why “step_one” can not be executed after startProcessInstanceByKey has been called.
  2. If I set “step_one” flowable:async=“false”, the execution variable is null. If set async=“true”, the execution variable is not null (code like this:)

Deployment deployment = repositoryService.createDeployment().addClasspathResource(“bpmn/SendEvent.bpmn”).deploy();
ProcessInstance pi = runtimeService.startProcessInstanceByKey(“SendEvent”);
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(pi.getId())
.activityId(“step_one”)
.singleResult();
assertNotNull(execution);
Thread.sleep(5000);
runtimeService.triggerAsync(execution.getId());
Thread.sleep(5000);

  1. after triggerAsync called, nothing happened. “sendEventService.sendMessage” has been called.

My bpmn like this:

<?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:xsd=“http://www.w3.org/2001/XMLSchema” xmlns:flowable=“http://flowable.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.flowable.org/processdef”>
<process id=“SendEvent” name=“SendEvent” isExecutable=“true”>
<startEvent id=“startEvent1”></startEvent>
<serviceTask id=“step_one” name=“step_one_name” flowable:async=“true” flowable:triggerable=“true” flowable:expression="#{sendEventService.sendMessage(execution, ‘test_app’, ‘test_firstEvent’)}"></serviceTask>
<sequenceFlow id=“sid-C43EA3A5-7F38-48B8-B091-112C6632B064” sourceRef=“startEvent1” targetRef=“step_one”></sequenceFlow>
<serviceTask id=“step_two” name=“step_two_name” flowable:async=“false” flowable:triggerable=“true” flowable:expression="#{sendEventService.sendMessage(execution, ‘test_app’, ‘test_secondEvent’)}"></serviceTask>
<sequenceFlow id=“sid-AD35CE48-AB59-4C40-9DA1-91B21F1463F9” sourceRef=“step_one” targetRef=“step_two”></sequenceFlow>
<endEvent id=“sid-FDDCC035-C01D-41D2-9867-39D78F064B50”></endEvent>
<sequenceFlow id=“sid-370A3246-FDBA-467E-86F4-BB131A80DB69” sourceRef=“step_two” targetRef=“sid-FDDCC035-C01D-41D2-9867-39D78F064B50”></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id=“BPMNDiagram_SendEvent”>
<bpmndi:BPMNPlane bpmnElement=“SendEvent” id=“BPMNPlane_SendEvent”>
<bpmndi:BPMNShape bpmnElement=“startEvent1” id=“BPMNShape_startEvent1”>
<omgdc:Bounds height=“30.0” width=“30.0” x=“100.0” y=“163.0”></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=“step_one” id=“BPMNShape_step_one”>
<omgdc:Bounds height=“80.0” width=“100.0” x=“257.0” y=“135.0”></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=“step_two” id=“BPMNShape_step_two”>
<omgdc:Bounds height=“80.0” width=“100.0” x=“506.0” y=“130.0”></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement=“sid-FDDCC035-C01D-41D2-9867-39D78F064B50” id=“BPMNShape_sid-FDDCC035-C01D-41D2-9867-39D78F064B50”>
<omgdc:Bounds height=“28.0” width=“28.0” x=“690.0” y=“156.0”></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement=“sid-AD35CE48-AB59-4C40-9DA1-91B21F1463F9” id=“BPMNEdge_sid-AD35CE48-AB59-4C40-9DA1-91B21F1463F9”>
<omgdi:waypoint x=“356.9499999999986” y=“173.995983935743”></omgdi:waypoint>
<omgdi:waypoint x=“505.99999999999847” y=“171.00301204819277”></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=“sid-370A3246-FDBA-467E-86F4-BB131A80DB69” id=“BPMNEdge_sid-370A3246-FDBA-467E-86F4-BB131A80DB69”>
<omgdi:waypoint x=“605.95” y=“170.0”></omgdi:waypoint>
<omgdi:waypoint x=“690.0” y=“170.0”></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement=“sid-C43EA3A5-7F38-48B8-B091-112C6632B064” id=“BPMNEdge_sid-C43EA3A5-7F38-48B8-B091-112C6632B064”>
<omgdi:waypoint x=“129.9482124561182” y=“177.76565302378518”></omgdi:waypoint>
<omgdi:waypoint x=“256.9999999999982” y=“175.78046875000004”></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

Hi,

The “triggerable” setting currently works for a Java delegate implementing the TriggerableActivityBehavior interface.

Please, have a look at this unit test:

Also, to the associated process diagram

I hope this helps to clarify the triggerable service task .

Regards,
Jorge Mora.

1 Like

Hello,
You can have a look at this topic:


HTH
Best Regards
William

Thank you for reply. I got it. My UT is passed :slight_smile:

@ jorge.mora With reference to your mention about triggerable works only for Java delegate, can you please let me know how to use triggerable for a http service task . I don’t have any java classes . Everything is handled in bpmn alone. Also in flowable doc there is no detailed explanation about trigger can be used with only java delegate implementing the TriggerableActivityBehavior. Can you throw some pointers on this. Thanks in advance

I think that you can have a look at the answer from @pstapleton for Camel tasks. You can try creating your own ActivityBehavior based on the original HttpActivityBehavior and add the triggerable behavior. I have not tried that by myself but it must work.

Thank you Jorge! I will try with your approach .

1 Like

Will there be support for serviceTasks with expressions? We heavily rely on expressions (${bean.method()}) and would also need the triggerable flag.

As I see, the org.flowable.engine.impl.bpmn.behavior.ServiceTaskExpressionActivityBehavior
class does not use the triggerable attribute. Would it be fine to just not call leave when triggerable is true (in execute()) and do nothing in trigger()?

@donkon, that would most certainly be doable. However, how do you plan do call the trigger method? In order to trigger an instance you would need to know the executionId

I have the executionId and would use the runtimeService.trigger() method. Would that work?

@filiphr it works this way:

public class ServiceTaskExpressionTriggerableActivityBehavior extends ServiceTaskExpressionActivityBehavior {

/** Serial. */
private static final long serialVersionUID = 9175468903749206291L;

private boolean triggerable;

public ServiceTaskExpressionTriggerableActivityBehavior(ServiceTask serviceTask, Expression expression, Expression skipExpression) {
	super(serviceTask, expression, skipExpression);
	this.triggerable  = serviceTask.isTriggerable();
}

@Override
public void trigger(DelegateExecution execution, String signalName, Object signalData) {
	super.leave(execution);
}

@Override
public void leave(DelegateExecution execution) {
	if (!this.triggerable) {
		super.leave(execution);
	}
}

}

Could this functionality be integrated in the flowable code base (nothing special here)?

Thanks for the snippet @donkon. I think that adding support for triggerable in the ServiceTaskExpressionTriggerableActivityBehavior. Seems like you already know what needs to be done. Would you be interested in providing a PR with this addition?

sure:

Thanks a lot @donkon. This has been merged into master.

Hi All,

We have a requirement where in we need to call custom java code from service task. This custom java code does some business logic. We want the process to wait when this happens and we plan to trigger the process again after our business logic is done.

I figured that using service task with flowable:triggerable=“true” flowable:async=“true” set. Below is the sample BPMN I have . This is just a POC which depicts what we want to achieve.

<?xml version="1.0" encoding="UTF-8"?>
<definitions typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/test" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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">
	<process id="ApprovalProcessSimple" isExecutable="true">
		
		<startEvent id="Start_Default"/>
		
		<serviceTask id="Start" flowable:delegateExpression="${serviceDelegate}">
			<extensionElements>
				<flowable:field name="taskDescription" stringValue="StartTask"/>
			</extensionElements>
		</serviceTask>

		<serviceTask id="ApprovedNode" flowable:delegateExpression="${asyncServiceDelegate}"  flowable:triggerable="true" flowable:async="true">
			<extensionElements>
				<flowable:field name="taskDescription" stringValue="AsynNodeTaskTriggerSync"/>
			</extensionElements>
		</serviceTask>
		
			<serviceTask id="ConfirmNode" flowable:delegateExpression="${serviceDelegate}">
			<extensionElements>
				<flowable:field name="taskDescription" stringValue="ConfirmNode"/>
			</extensionElements>
		</serviceTask>
		
		<endEvent id="End"/>
		
		<sequenceFlow sourceRef="Start_Default" targetRef="Start"/>
		<sequenceFlow sourceRef="Start" targetRef="ApprovedNode"/>
		<sequenceFlow sourceRef="ApprovedNode" targetRef="ConfirmNode"/>
		<sequenceFlow sourceRef="ConfirmNode" targetRef="End"/>
	</process>
	<bpmndi:BPMNDiagram id="BPMNDiagram_ApprovedNodeManually">
		<bpmndi:BPMNPlane bpmnElement="ApprovedNodeManually" id="BPMNPlane_ApprovedNodeManually"/>
	</bpmndi:BPMNDiagram>
</definitions>

The delegate for async task is :

@Component
public class AsyncServiceDelegate implements TriggerableActivityBehavior, JavaDelegate, Serializable {

private static final long serialVersionUID = 1L;

private final Logger logger = LoggerFactory.getLogger(AsyncServiceDelegate.class);

private Expression taskDescription;

@Override
public void execute(DelegateExecution execution) {

    String taskDescriptionValue = ((String) taskDescription.getValue(execution));
    logger.debug(LogMarker.ENTRY, "In execute method of AsynServiceDelegate");
    logger.debug("Current activity id is : {} ", execution.getCurrentActivityId());
    logger.debug("Current task descrption is {}", taskDescriptionValue);
    logger.debug("Current process id is : {}", execution.getProcessInstanceId());
    logger.debug("Execution id is : {}", execution.getId());

}

@Override
public void trigger(DelegateExecution execution, String signalEvent, Object signalData) {
    logger.debug("In trigger code inside delegate");

}

After we deploy and start the process and I see that the process reaches
till AsyncServiceDelegate and does execute() and goes to wait state. It does not reach the ConfirmNode which is correct.

Now I am doing the below to trigger the process so that it continues execution . However this is not happening.

Execution execution = runtimeService.createExecutionQuery().processInstanceId(processId).activityId(actvityId).singleResult();
logger.debug("Execution id for triggering is : {} ", execution.getId());
runtimeService.trigger(execution.getId());

I see the call reaches AsyncServiceDelegate.trigger() method but nothing happens after that. How do I make the process continue to the ConfirmNode.

a> Is this because leave(execution) is not called?
b> Will the above fix help us?
c> Is there a workaround for this if we are not able to take the above mentioned code fix?

Correct. Once you implement one of the *ActivityBehavior interface, you’re responsible for the routing logic (see the ‘internal’ section at https://flowable.com/open-source/docs/bpmn/ch07b-BPMN-Constructs/#implementation)