XTi Blog

Flowable External Worker Spring Boot Starter

Geschreven door Nico Van de Zande | 29/03/21 16:02

Het External Worker patroon is gebaseerd op het feit dat de workflow engine taken creëert op een intern subject (voorgedefinieerd in de definitie van het proces). De afhandeling van deze taken wordt toevertrouwd aan een externe werker, een systeem of werker buiten de workflow engine. In tegenstelling tot andere technieken pusht de workflow engine geen taken naar externe werkers, maar zullen de externe werkers zelf taken halen uit het onderwerp of de onderwerpen die de workflow engine beschikbaar stelt. Zowel in de open source Flowable Modeler tool als in de commerciële Flowable Design tool (zie screenshot), kan een "External Worker Task" worden opgenomen in het BPMN proces, en kan een "job topic" worden ingesteld dat taken aanbiedt voor het externe werker proces. Dit resulteert in eenvoudig modelleren, geen wachtrijen, geen externe afhankelijkheden nodig, alleen de Flowable open source runtime engine.

Om externe taken op te halen en af te handelen vanuit een extern werkproces, moet een verbinding gemaakt worden met de workflow engine.

 

Er zijn twee manieren die Flowable ons biedt om dit te bewerkstelligen.

Met behulp van de Java API, die rechtstreeks verbinding maakt met de workflow engine.

Het gebruik van de Java API geniet niet de voorkeur bij het gebruik van externe taken. Het is immers de bedoeling om de taken buiten de workflow engine om af te handelen en zo min mogelijk dependency te hebben tussen het afhandelen van de taken en de workflow engine. Het ontneemt ook het feit dat een werker polyglot kan zijn.

Gebruik van de Flowable Rest API

Met behulp van de Flowable Rest API is het mogelijk om een externe worker te maken die onafhankelijk is van taal en architectuur.

Uitdaging: Configuratie en kennis van de Flowable Rest API voor externe taken


Eén van de problemen die overblijft met de Flowable Rest API, is dat een client moet worden geconfigureerd en dat verschillende verzoeken en antwoorden bekend moeten zijn. Hier moeten de endpoints voor de verschillende behandelingen correct worden aangeroepen.

Als in de architectuur verschillende werkers zijn gedefinieerd, moet de configuratie voor elke werker worden herhaald en kan dit in de loop van de tijd moeilijker te onderhouden worden.

Oplossing: Een spring boot starter die het voor jou configureert.

De Flowable External Worker spring-boot starter zorgt ervoor dat er geen diepe technische kennis van de Flowable Rest API nodig is, zoals de benodigde endpoints of het samenstellen van requests. Ook de benodigde configuratie wordt op een logische plaats bijgehouden.

 

Gebruik en voorbeeld

Maven dependency
De eerste stap om deze starter te gebruiken is om deze te importen in je worker applicatie als een maven dependency:

<dependency>
<groupId>com.xti.flowable</groupId>
<artifactId>flowable-externalworker-client-spring-boot-starter</artifactId>
<version>0.0.1 </version>
</dependency>

Hiervoor moet de XTi maven repository toegevoegd worden aan de pom.xml:

<repositories>
    <!-- XTi opensource maven repository -->
    <repository>
        <id>io.cloudrepo.xti.opensource</id>
        <url>https://maven.xt-i.cloud/public/repositories/opensource/</url>
    </repository>
</repositories>

Properties

In de application properties, specifieer je de url van van de flowable engine en de workerId van je applicatie:

flowable.external.url = http://localhost:8080/external-job-api
flowable.external.workerId = SpringBootFlowableWorker1


Heb je de REST API van Flowable beveiligd met Basic Authentication, dan kan je ook de credentials hiervoor meegeven:

flowable.external.username=admin
flowable.external.password=test

De FlowableWorker annotation

Om de worker te definiëren maken we gebruik van de FlowableWorker annotation.
Deze annotation heeft verschillende fields:

Field naam

Omschrijving

Default waarde

topic

De topic waarvan de worker taken wilt verkrijgen.

 

maxTasks

Maximum aantal taken dat de worker zal bemachtigen in 1 call

10

lockDuration

De maximale tijd dat de worker een lock zal hebben op de taak. Het formaat is ISO-8601. PT10M vertaald naar 10 minuten.

PT10M

numberOfRetries

Het aantal pogingen als er een optimistische lock eception optreedt tijdens het verwerven van de taak.

10

scopeType

Verkrijg alleen maar taken van de gegeven scope.

 

Deze annotation moet op methode niveau worden gedefineeërd. De toepassing word hieronder uitgelegd.

De FlowableWorker toepassen op een methode

Om een worker te definiëren en jobs af te handelen annoteren we de corresponderende methode met @FlowableWorker. Deze methode accepteert slechts één parameter. Namelijk een van het type AcquiredJob. Nu kan de methode optreden als een Externe Werker en zal elke job door de methode worden uitgevoerd.

 

Voorbeeld van een methode die als Flowable Worker kan worden gebruikt:

@FlowableWorker(topic="topicToGetTasksFrom", lockDuration="PT5M")
public void execute ( AcquiredJob job ) {

Daarna kan het werk volgens deze methode worden afgehandeld en voltooid. De volgende methoden kunnen gebruikt worden de job te behandelen.

Methode

Parameters

Omschrijving

Resultaat

getVariables

-

Verkrijgen van variablen van deze job

Lijst van EngineVariable

complete

()
(variabelen)

Taak word gemarkeerd als “complete”

-

cmmnTerminate

()
(variabelen)

Cmmn taak word gemarkeerd als “terminate”

-

bpmnError

()
(variabelen, errorcode)

Taak word gemarkeerd met BPMN error

-

fail

()
(errorMessage, errorDetails, retries, retryTimeout)

Taak word gemarkeerd als gefaald.

-

 

In het volgende voorbeeld willen we 2 variabelen, die bestaan in het process, samenvoegen en teruggeven aan het process:

@FlowableWorker(topic="topicToGetJobFrom")
public void execute(AcquiredJob job) {

List<EngineVariable> variables = job.getVariables();
Optional<EngineVariable> variableA = variables.stream()
.filter(variable -> variable.getName().equals("variableA"))
.findFirst();
Optional<EngineVariable> variableB = variables.stream()
.filter(variable -> variable.getName().equals("variableB"))
.findFirst();

if(variableA.isPresent() && variableB.isPresent()) {
EngineVariable variableC = new EngineVariable();
variableC.setName("variableC");
variableC.setValue(variableA.get().getValue() + ":" + variableB.get().getValue());

List<EngineVariable> newVariables = new ArrayList<>();
newVariables.add(variableC);

job.complete(newVariables);

} else {
job.fail("Incorrect variables", "variable not found", 3, "PT5M");
}
}

De broncode van deze Spring Boot Starter is te vinden op github
Heb je nog vragen over dit artikel? Aarzel niet om ons even te contacteren.