{"id":419,"date":"2020-06-27T16:55:34","date_gmt":"2020-06-27T16:55:34","guid":{"rendered":"http:\/\/www.canchito-dev.com\/public\/blog\/?p=419"},"modified":"2021-05-02T13:37:15","modified_gmt":"2021-05-02T13:37:15","slug":"triggerable-custom-service-tasks-in-flowable","status":"publish","type":"post","link":"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/27\/triggerable-custom-service-tasks-in-flowable\/","title":{"rendered":"Triggerable Custom Service Tasks in Flowable"},"content":{"rendered":"<h1>Triggerable Custom Service Tasks in Flowable<\/h1>\n<p style=\"text-align: justify;\"><div class=\"perfect-pullquote vcard pullquote-align-full pullquote-border-placement-left\"><blockquote><p>In this tutorial, we will be implementing a triggerable custom service task in Flowable. A triggerable task, is one that when it is reached, it is executes its business logic, but once done, it enters a wait state. In order to leave this state, it must be triggered.<\/p><\/blockquote><\/div><\/p>\n<div>\n  <a class=\"donate-with-crypto\"\n     href=\"https:\/\/commerce.coinbase.com\/checkout\/faf64f90-2e80-46ee-aeba-0fde14cbeb46\"><br \/>\n    Buy Me a Coffee<br \/>\n  <\/a><br \/>\n  <script src=\"https:\/\/commerce.coinbase.com\/v1\/checkout.js?version=201807\">\n  <\/script>\n<\/div>\n<h2 style=\"text-align: justify;\">Contribute\u00a0Code<\/h2>\n<p style=\"text-align: justify;\">If you would like to become an active contributor to this project please follow these simple steps:<\/p>\n<ol>\n<li style=\"text-align: justify;\">Fork it<\/li>\n<li style=\"text-align: justify;\">Create your feature branch<\/li>\n<li style=\"text-align: justify;\">Commit your changes<\/li>\n<li style=\"text-align: justify;\">Push to the branch<\/li>\n<li style=\"text-align: justify;\">Create new Pull Request<\/li>\n<\/ol>\n<h2 style=\"text-align: justify;\">What you\u2019ll need<\/h2>\n<ul>\n<li style=\"text-align: justify;\">About 40 minutes<\/li>\n<li style=\"text-align: justify;\">A favorite IDE. In this post, we use <a href=\"https:\/\/www.jetbrains.com\/idea\/download\/index.html\">Intellij Community<\/a><\/li>\n<li style=\"text-align: justify;\"><a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\">JDK 7<\/a> or later. It can be made to work with JDK6, but it will need configuration tweaks. Please check the Spring Boot documentation<\/li>\n<\/ul>\n<h2 style=\"text-align: justify;\">Starting with Spring Initializr<\/h2>\n<p style=\"text-align: justify;\">For all Spring applications, it is always a good idea to start with the <a href=\"https:\/\/start.spring.io\/\">Spring Initializr<\/a>. The Initializr is an excellent option for pulling in all the dependencies you need for an application and does a lot of the setup for you. This example needs only the Spring Web, and H2 Database dependency. The following image shows the Initializr set up for this sample project:<\/p>\n<p>![Spring Initializr](images\/initializr.png)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"410\" data-permalink=\"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/12\/integrate-flowable-into-your-spring-boot-application\/initializr\/\" data-orig-file=\"https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png\" data-orig-size=\"1438,947\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"CANCHITO-DEV: Spring Initializr\" data-image-description=\"&lt;p&gt;CANCHITO-DEV: Spring Initializr&lt;\/p&gt;\n\" data-image-caption=\"&lt;p&gt;CANCHITO-DEV: Spring Initializr&lt;\/p&gt;\n\" data-medium-file=\"https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-300x198.png\" data-large-file=\"https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png\" class=\"aligncenter wp-image-410 size-full\" src=\"http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png\" alt=\"CANCHITO-DEV: Spring Initializr\" width=\"1438\" height=\"947\" srcset=\"https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png 1438w, https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-300x198.png 300w, https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png 1024w, https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-768x506.png 768w, https:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-624x411.png 624w\" sizes=\"auto, (max-width: 1438px) 100vw, 1438px\" \/><\/p>\n<p style=\"text-align: justify;\">The following listing shows the `pom.xml` file that is created when you choose Maven:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n  xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\r\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\r\n  &lt;parent&gt;\r\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt;\r\n    &lt;version&gt;2.2.7.RELEASE&lt;\/version&gt;\r\n    &lt;relativePath\/&gt; &lt;!-- lookup parent from repository --&gt;\r\n  &lt;\/parent&gt;\r\n  &lt;groupId&gt;com.canchitodev.example&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;spring-flowable-integration&lt;\/artifactId&gt;\r\n  &lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt;\r\n  &lt;packaging&gt;war&lt;\/packaging&gt;\r\n\r\n  &lt;name&gt;spring-flowable-integration&lt;\/name&gt;\r\n  &lt;description&gt;Demo project for Spring Boot using Flowable BPM&lt;\/description&gt;\r\n\r\n  &lt;organization&gt;\r\n    &lt;name&gt;Canchito Development&lt;\/name&gt;\r\n    &lt;url&gt;http:\/\/www.canchito-dev.com&lt;\/url&gt;\r\n  &lt;\/organization&gt;\r\n\r\n  &lt;issueManagement&gt;\r\n    &lt;system&gt;Canchito Development&lt;\/system&gt;\r\n    &lt;url&gt;https:\/\/github.com\/canchito-dev\/spring-flowable-integration\/issues&lt;\/url&gt;\r\n  &lt;\/issueManagement&gt;\r\n\r\n  &lt;url&gt;http:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/10\/integrate-flowable-into-your-spring-boot-application\/&lt;\/url&gt;\r\n\r\n  &lt;properties&gt;\r\n    &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\r\n    &lt;project.reporting.outputEncoding&gt;UTF-8&lt;\/project.reporting.outputEncoding&gt;\r\n    &lt;java.version&gt;1.8&lt;\/java.version&gt;\r\n    &lt;flowable.version&gt;6.5.0&lt;\/flowable.version&gt;\r\n  &lt;\/properties&gt;\r\n\r\n  &lt;dependencies&gt;\r\n    &lt;!-- Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container --&gt;\r\n\r\n    &lt;!-- H2 Database Engine --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;com.h2database&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;h2&lt;\/artifactId&gt;\r\n      &lt;scope&gt;runtime&lt;\/scope&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- H2 Database Engine --&gt;\r\n\r\n    &lt;!-- Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-tomcat&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web --&gt;\r\n\r\n    &lt;!-- Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\r\n      &lt;scope&gt;test&lt;\/scope&gt;\r\n      &lt;exclusions&gt;\r\n        &lt;exclusion&gt;\r\n          &lt;groupId&gt;org.junit.vintage&lt;\/groupId&gt;\r\n          &lt;artifactId&gt;junit-vintage-engine&lt;\/artifactId&gt;\r\n        &lt;\/exclusion&gt;\r\n      &lt;\/exclusions&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito --&gt;\r\n\r\n    &lt;!-- Flowable Spring Boot Starter Basic --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.flowable&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;flowable-spring-boot-starter-basic&lt;\/artifactId&gt;\r\n      &lt;version&gt;${flowable.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- Flowable Spring Boot Starter Basic --&gt;\r\n  &lt;\/dependencies&gt;\r\n\r\n  &lt;build&gt;\r\n    &lt;plugins&gt;\r\n      &lt;plugin&gt;\r\n        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;spring-boot-maven-plugin&lt;\/artifactId&gt;\r\n      &lt;\/plugin&gt;\r\n    &lt;\/plugins&gt;\r\n  &lt;\/build&gt;\r\n\r\n&lt;\/project&gt;<\/pre>\n<p style=\"text-align: justify;\">Follow<span style=\"font-size: 1rem;\">\u00a0our post <\/span><a style=\"font-size: 1rem;\" href=\"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/10\/integrate-flowable-into-your-spring-boot-application\/\">Integrate Flowable into your Spring Boot Application<\/a><span style=\"font-size: 1rem;\">, to see how to integrate Flowable.<\/span><\/p>\n<h4 style=\"text-align: justify;\">Introducing the Triggerable Custom Service Task<\/h4>\n<p dir=\"auto\" style=\"text-align: justify;\" data-sourcepos=\"126:1-126:389\">It is very common to interact with other services or applications by sending a Kafka message or making a HTTP request for instance. During this interaction, once the process instance has executed the delegate&#8217;s business logic, it should go into a wait state. At some moment in the future, the external service will return a response and the process instance continues to the next activity.<\/p>\n<p dir=\"auto\" style=\"text-align: justify;\" data-sourcepos=\"128:1-128:279\">In the default BPMN notation, this is modeled as a service task followed by a receive task. Nevertheless, this introduces some racing conditions if for instance the external service responses too fast and the process instance has not persisted and the receive task is not active.<\/p>\n<p dir=\"auto\" style=\"text-align: justify;\" data-sourcepos=\"130:1-130:659\">In order to solve this, Flowable has come up with a custom attribute (<em>flowable:triggerable<\/em>) available for use on service tasks. What is does is simple. It joins the behavior of a service task together with a receive task. This means that when the process instance reaches this service task, it will execute the logic found in the <em>method(DelegateExecution)<\/em> function, as it normally does, and then waits for an external trigger before it continues to the next activity. If the async attribute is also set to true for a triggerable service task, the process instance state is first persisted and then the service task logic will be executed in an async job.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;serviceTask id=\"aTriggerableServiceTask\"\r\n  flowable:expression=\"#{myService.doSomething()}\" \r\n  flowable:triggerable=\"true\" \r\n  flowable:async=\"true\" \r\n\/&gt;\r\n<\/pre>\n<p style=\"text-align: justify;\">To avoid optimistic lock exceptions, it is recommended to trigger it asynchronously. By default, an asynchronous job is exclusive, meaning that the process instance will be locked. This guarantees that no other activity on the process instance interfere with the trigger logic.<\/p>\n<h2>Creating a Triggerable Custom Service Task<\/h2>\n<p style=\"text-align: justify;\">The first thing you need to do, is create a class and call it <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">TriggerableServiceTask<\/code>. This class will implement <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">JavaDelegate<\/code>, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">TriggerableActivityBehavior<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Serializable<\/code>. Once you have done this, you will need to override the methods <em>execute<\/em> and <em>trigger<\/em>. Here is the example code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Service(\"triggerableServiceTask\")\r\n@Scope(\"prototype\")\r\npublic class TriggerableServiceTask implements JavaDelegate, TriggerableActivityBehavior, Serializable {\r\n\r\n    @Override\r\n    public void execute(DelegateExecution execution) {\r\n        incrementCount(execution);\r\n    }\r\n\r\n    @Override\r\n    public void trigger(DelegateExecution execution, String signalName, Object signalData) {\r\n        incrementCount(execution);\r\n    }\r\n\r\n    public void incrementCount(DelegateExecution execution) {\r\n        String variableName = \"count\";\r\n        int count = 0;\r\n        if (execution.hasVariable(variableName)) {\r\n            count = (int) execution.getVariable(variableName);\r\n        }\r\n        count++;\r\n        execution.setVariable(variableName, count);\r\n    }\r\n}<\/pre>\n<p style=\"text-align: justify;\">The logic is simple. When the <em>execute<\/em> method is reached, it calls the <em>incrementCount<\/em>, which it creates a process variable (if it does not exists) named &#8220;count&#8221;, increases its current value by one, and updates it so that it is available during the process execution.<\/p>\n<p style=\"text-align: justify;\">When the <em>trigger<\/em> method is reached, the same logic as with the <em>execute<\/em> method is followed.<\/p>\n<h2>Testing the Task<\/h2>\n<p style=\"text-align: justify;\">To test it, create a file named triggerable-custom-service-task.bpmn20<em>.xml<\/em> inside the folder <code>src\/main\/resources\/processes<\/code>. This is a dummy process definition. The content of the file is below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;definitions\r\n        xmlns=\"http:\/\/www.omg.org\/spec\/BPMN\/20100524\/MODEL\"\r\n        xmlns:flowable=\"http:\/\/flowable.org\/bpmn\"\r\n        targetNamespace=\"Examples\"&gt;\r\n    &lt;process id=\"triggerableCustomServiceTask\" name=\"Triggerable Custom Service Task\"&gt;\r\n        &lt;startEvent id=\"theStart\" \/&gt;\r\n        &lt;sequenceFlow sourceRef=\"theStart\" targetRef=\"service1\" \/&gt;\r\n        &lt;serviceTask id=\"service1\" flowable:delegateExpression=\"${triggerableServiceTask}\" flowable:async=\"true\" flowable:triggerable=\"true\"\/&gt;\r\n        &lt;sequenceFlow sourceRef=\"service1\" targetRef=\"usertask1\" \/&gt;\r\n        &lt;userTask id=\"usertask1\" name=\"Task A\"\/&gt;\r\n        &lt;sequenceFlow sourceRef=\"usertask1\" targetRef=\"theEnd\" \/&gt;\r\n        &lt;endEvent id=\"theEnd\" \/&gt;\r\n    &lt;\/process&gt;\r\n&lt;\/definitions&gt;<\/pre>\n<p style=\"text-align: justify;\">For testing the workflow, we will use Flowable&#8217;s API. But first, we need to add jUnit dependencies. Open the <code>pom.xml<\/code> file and add:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;dependency&gt;\r\n  &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;junit-jupiter-api&lt;\/artifactId&gt;\r\n  &lt;version&gt;${junit.jupiter.version}&lt;\/version&gt;\r\n  &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n\r\n&lt;dependency&gt;\r\n  &lt;groupId&gt;junit&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;junit&lt;\/artifactId&gt;\r\n  &lt;version&gt;${junit.version}&lt;\/version&gt;\r\n  &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n\r\n&lt;dependency&gt;\r\n  &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;\r\n  &lt;version&gt;${junit.jupiter.version}&lt;\/version&gt;\r\n  &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n\r\n&lt;dependency&gt;\r\n  &lt;groupId&gt;org.junit.vintage&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;junit-vintage-engine&lt;\/artifactId&gt;\r\n  &lt;version&gt;${junit.vintage.version}&lt;\/version&gt;\r\n  &lt;scope&gt;test&lt;\/scope&gt;\r\n&lt;\/dependency&gt;\r\n\r\n&lt;dependency&gt;\r\n  &lt;groupId&gt;org.awaitility&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;awaitility&lt;\/artifactId&gt;\r\n&lt;\/dependency&gt;<\/pre>\n<p>And under the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;build&gt;<\/code> section, add the following plugins:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;plugin&gt;\r\n  &lt;artifactId&gt;maven-surefire-plugin&lt;\/artifactId&gt;\r\n  &lt;version&gt;2.22.2&lt;\/version&gt;\r\n&lt;\/plugin&gt;\r\n\r\n&lt;plugin&gt;\r\n  &lt;artifactId&gt;maven-failsafe-plugin&lt;\/artifactId&gt;\r\n  &lt;version&gt;2.22.2&lt;\/version&gt;\r\n&lt;\/plugin&gt;<\/pre>\n<p>Afterwards, create a testing class under folder <code>src\/main\/test\/java<\/code>. In our case, we named the class <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">FlowableTriggerableCustomServiceTaskApplicationTests<\/code>. And here is the code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@SpringBootTest\r\nclass FlowableTriggerableCustomServiceTaskApplicationTests {\r\n\r\n  @Autowired\r\n  private RuntimeService runtimeService;\r\n\r\n  @Autowired\r\n  private TaskService taskService;\r\n\r\n  @Autowired\r\n  private HistoryService historyService;\r\n\r\n  @Test\r\n  @Deployment(resources = \"processes\/triggerable-custom-service-task.bpmn20.bpmn\")\r\n  void testTriggerableCustomServiceTask() {\r\n    \/\/ Start a new process instance\r\n    ProcessInstance processInstance = this.runtimeService.startProcessInstanceByKey(\"triggerableCustomServiceTask\");\r\n\r\n    \/\/ Check if triggarable custom service task was reached\r\n    await().atMost(30L, TimeUnit.SECONDS).until(\r\n        () -&gt; this.runtimeService.createExecutionQuery()\r\n            .activityId(\"service1\")\r\n            .processInstanceId(processInstance.getProcessInstanceId())\r\n            .singleResult() != null\r\n    );\r\n\r\n    \/\/ Get the value of the variable 'count' before the trigger\r\n    HistoricVariableInstance historicVariableInstance = this.historyService.createHistoricVariableInstanceQuery()\r\n        .processInstanceId(processInstance.getProcessInstanceId())\r\n        .variableName(\"count\")\r\n        .singleResult();\r\n\r\n    \/\/ Let's see the value of 'count' as it was modified in the execute method\r\n    System.out.println(String.format(\"Before trigger: %s\", historicVariableInstance.getValue()));\r\n\r\n    \/\/ We need the execution Id of the triggerable service task\r\n    Execution execution = this.runtimeService.createExecutionQuery()\r\n        .processInstanceId(processInstance.getProcessInstanceId())\r\n        .activityId(\"service1\")\r\n        .singleResult();\r\n\r\n    \/\/ Trigger the service task.\r\n    this.runtimeService.trigger(execution.getId());\r\n\r\n    \/\/ Get the value of the variable 'count' after the trigger\r\n    historicVariableInstance = this.historyService.createHistoricVariableInstanceQuery()\r\n        .processInstanceId(processInstance.getProcessInstanceId())\r\n        .variableName(\"count\")\r\n        .singleResult();\r\n\r\n    \/\/ Let's see the value of 'count' as it was modified in the trigger method\r\n    System.out.println(String.format(\"After trigger: %s\", historicVariableInstance.getValue()));\r\n\r\n    \/\/ Check if the user task was reached\r\n    await().atMost(30L, TimeUnit.SECONDS).until(\r\n        () -&gt; this.runtimeService.createExecutionQuery()\r\n            .activityId(\"usertask1\")\r\n            .processInstanceId(processInstance.getProcessInstanceId())\r\n            .singleResult() != null\r\n    );\r\n\r\n    \/\/ Get the task from the TaskService\r\n    Task task = this.taskService.createTaskQuery()\r\n        .processInstanceId(processInstance.getProcessInstanceId())\r\n        .taskName(\"Task A\")\r\n        .singleResult();\r\n\r\n    \/\/ Complete the user task\r\n    this.taskService.complete(task.getId());\r\n\r\n    \/\/ Make sure the process has ended\r\n    await().atMost(30L, TimeUnit.SECONDS).until(\r\n        () -&gt; this.historyService.createHistoricProcessInstanceQuery()\r\n            .processInstanceId(processInstance.getProcessInstanceId())\r\n            .finished()\r\n            .singleResult() != null\r\n    );\r\n  }\r\n}<\/pre>\n<p style=\"text-align: justify;\">The test is very simple. Here are the steps that we performed. They are also included as comments in the sample code:<\/p>\n<ol>\n<li style=\"text-align: justify;\">Start a process instance<\/li>\n<li>Check is the triggerable custom service task was reached<\/li>\n<li>Get the value of the variable &#8216;count&#8217; before the trigger<\/li>\n<li>Let&#8217;s see the value of &#8216;count&#8217; as it was modified in the execute method, by printing it in the log console<\/li>\n<li>Get\u00a0 the execution Id of the triggerable custom service task<\/li>\n<li>Trigger the service task<\/li>\n<li>Get the value of the variable &#8216;count&#8217; after the trigger<\/li>\n<li>Let&#8217;s see the value of &#8216;count&#8217; as it was modified in the trigger method, by printing it in the log console<\/li>\n<li>Check if the user task was reached<\/li>\n<li>Get the task from the TaskService<\/li>\n<li>Complete the user task<\/li>\n<li>Make sure the process has ended<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">If you execute the test, you should see these lines logged:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">Before trigger: 1\r\nAfter trigger: 2<\/pre>\n<h2 style=\"text-align: justify;\">Summary<\/h2>\n<p style=\"text-align: justify;\">In this post, we have shown how to create a custom and triggerable service task Flowable<span style=\"font-size: 1rem;\">. We hope that, even though this was a very basic introduction, you understood how to use and configure them. We will try to go deeper into Flowable in upcoming posts.<\/span><\/p>\n<p style=\"text-align: justify;\">Please feel free to contact us. We will gladly response to any doubt or question you might have.<\/p>\n<p>Source code can be found in our <a href=\"https:\/\/github.com\/canchito-dev\/flowable-triggerable-custom-service-task\">GitHub<\/a> repository.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we will be implementing a triggerable custom service task in Flowable. A triggerable task, is one that when it is reached, it is executes its business logic, but once done, it enters a wait state. In order to leave this state, it must be triggered.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[30,61,47,3,65],"tags":[],"class_list":["post-419","post","type-post","status-publish","format-standard","hentry","category-flowable","category-flowable-bpm","category-open-source","category-spring","category-spring-boot"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p8EwXo-6L","jetpack-related-posts":[{"id":372,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/07\/create-custom-service-tasks-for-flowable\/","url_meta":{"origin":419,"position":0},"title":"Create Custom Service Tasks for Flowable","author":"canchitodev","date":"June 7, 2020","format":false,"excerpt":"In\u00a0this\u00a0tutorial,\u00a0we\u00a0will\u00a0be\u00a0implementing\u00a0a\u00a0custom\u00a0service\u00a0task\u00a0in\u00a0Flowable\u00a0","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Spring Initializr","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=700%2C400 2x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=1050%2C600 3x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=1400%2C800 4x"},"classes":[]},{"id":477,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/27\/use-flowable-apps-with-a-custom-rest-api\/","url_meta":{"origin":419,"position":1},"title":"Use Flowable Apps with a Custom REST API","author":"canchitodev","date":"June 27, 2020","format":false,"excerpt":"In this post, you will learn how configure Flowable's apps to use your custom Spring Boot REST API as a backend engine. All this, in a dockerized environment.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Tomcat Main","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=700%2C400 2x"},"classes":[]},{"id":184,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2018\/03\/30\/asynchronous-service-invocation-using-flowable\/","url_meta":{"origin":419,"position":2},"title":"Asynchronous Service Invocation using Flowable","author":"canchitodev","date":"March 30, 2018","format":false,"excerpt":"In this article, I will explain one possible method to solved some \"limitations\" encountered during the integration and implementation of\u00a0Flowable BPM, when executing long-running tasks, by implementing the Signallable Flowable Behavior and a database table as a task queue. Similar behavior can be achieved using Flowable's send task and receive\u2026","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Task Queue Service","src":"https:\/\/i0.wp.com\/canchito-dev.com\/img\/cwm\/userguide\/canchito_dev_task_queue_service.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":356,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2019\/07\/05\/run-flowable-bpm-using-docker-and-mysql\/","url_meta":{"origin":419,"position":3},"title":"Run Flowable BPM using Docker and MySQL","author":"canchitodev","date":"July 5, 2019","format":false,"excerpt":"In this article, you will learn how to compile Flowable source code using MySQL as database source, and generate valid Docker images. Once you have the images, we will use Docker Compose for defining and running a multi-container Docker applications.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":370,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/12\/integrate-flowable-into-your-spring-boot-application\/","url_meta":{"origin":419,"position":4},"title":"Integrate Flowable into your Spring Boot Application","author":"canchitodev","date":"May 12, 2020","format":false,"excerpt":"In\u00a0this\u00a0tutorial,\u00a0we\u00a0will\u00a0be\u00a0integrating\u00a0Flowable's\u00a0BPM\u00a0engine\u00a0into\u00a0our\u00a0Spring\u00a0Boot\u00a0application.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Spring Initializr","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=525%2C300 1.5x"},"classes":[]},{"id":458,"url":"https:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/14\/deploying-flowable-in-a-docker-container-and-mysql-part-2\/","url_meta":{"origin":419,"position":5},"title":"Deploying Flowable in a Docker Container and MySQL (Part 2)","author":"canchitodev","date":"May 14, 2020","format":false,"excerpt":"This is the second part of our \"Deploying Flowable in a Docker Container and MySQL\" series. In this post, you will learn how to deploy Flowable's war files in a container running Tomcat, and connecting to another container running use MySQL database.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"https:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Tomcat Main","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/tomcat_main_page-1.png?resize=700%2C400 2x"},"classes":[]}],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/comments?post=419"}],"version-history":[{"count":9,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/419\/revisions"}],"predecessor-version":[{"id":533,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/419\/revisions\/533"}],"wp:attachment":[{"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/media?parent=419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/categories?post=419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/tags?post=419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}