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 |
() |
Taak word gemarkeerd als “complete” |
- |
cmmnTerminate |
() |
Cmmn taak word gemarkeerd als “terminate” |
- |
bpmnError |
() |
Taak word gemarkeerd met BPMN error |
- |
fail |
() |
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.