Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#267 Implementierung einer Workflow-Engine #285

Conversation

RemodifyBerlin
Copy link
Contributor

Dieser Pull Request führt die Integration der Camunda Workflow Engine in einem Docker Container in das Projekt ein.

Die Änderungen umfassen Aktualisierungen der Datei README.md, das Hinzufügen von Camunda-Diensten in docker-compose.yml und die Erstellung einer Testklasse für die Demonstration von Camunda-API-Interaktionen.

Camunda-Integration:

  • Detaillierte Anweisungen in README.md hinzugefügt, wie man Camunda mit Docker betreibt, mit ihm über die REST API interagiert und Tests ausführt.
  • Die Datei docker-compose.yml wurde aktualisiert, um einen neuen Camunda-Dienst einzubinden, ihn auf Port 8081 freizugeben und ihn so zu konfigurieren, dass Demodaten und Beispielprozesse deaktiviert werden.
  • Hinzufügen einer neuen BPMN-Prozessdatei open-ticket.bpmn, um einen BeispielWorkflow für das Öffnen eines Tickets zu definieren.
  • Hinzufügen einer neuen Testklasse CamundaApiTest zur Demonstration der Interaktion mit der Camunda-Engine, einschließlich des Starts von Prozessen und der Ausführung von Aufgaben.
  • Aktualisierte pom.xml, um CamundaApiTest von bestimmten Builds auszuschließen und fügte Abhängigkeiten um REST-Interaktionen zu ermöglichen.

Der deployde Prozess ist unter dem Camunda Cockpit sichtbar. Hier ist der Prozess zu sehen:

Bildschirmfoto 2024-12-16 um 17 30 17

RemodifyBerlin and others added 9 commits December 16, 2024 14:55
- Introduced Camunda as a service in docker-compose.yml
- Added dependencies for Jersey client in pom.xml
- Created CamundaApiTest to validate process lifecycle
- Updated README.md with Camunda usage instructions
- Excluded CamundaApiTest from certain build configurations
@astanik astanik added the enhancement New feature or request label Dec 17, 2024
@astanik astanik linked an issue Dec 17, 2024 that may be closed by this pull request
@astanik
Copy link
Contributor

astanik commented Dec 19, 2024

@RemodifyBerlin Unfortunately I don't see any project integration in this PR?

Take look at https://docs.quarkiverse.io/quarkus-zeebe/dev/index.html or https://docs.camunda.io/docs/apis-tools/community-clients/quarkus/

@astanik astanik requested a review from gflachs December 19, 2024 07:53
@RemodifyBerlin
Copy link
Contributor Author

RemodifyBerlin commented Dec 19, 2024

@RemodifyBerlin Unfortunately I don't see any project integration in this PR?

Take look at https://docs.quarkiverse.io/quarkus-zeebe/dev/index.html or https://docs.camunda.io/docs/apis-tools/community-clients/quarkus/

@astanik Integrating Camunda Engine with Quarkus proved to be a pain due to runtime errors, version conflicts, and database configuration requirements for camunda (READ_COMMITTED) that disrupted tests and services.

I should have read more into the limitations of quarkus and camunda (here) and read more experiences about the integration, which are mixed.

Refactoring the project to accommodate these issues felt unnecessary for a simple proof of concept designed to demonstrate the potential of a workflow engine. The limited community support further compounded the delays, and I couldn’t find solutions within the available timeframe.

To move forward and finish this feature, I switched to using Docker for Camunda Engine, providing a simpler, more flexible setup.

I hope my approach offers atleast valuable insights for future developers tackling this in the project.

Copy link
Contributor

@gflachs gflachs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ein Review dieses PR ist schwieirig, da er nicht zu der im Issue beschriebenen Lösung beiträgt und auch keine Integration in das Projekt beinhaltet.

Basierend auf dem im Issue beschrieben Ziel und dem von @astanik bereits verlinkten Ressourcen habe ich einmal ein Testsetup erstellt, welches das Problem lösen sollte. Ich werde dieses hier nun beschreiben, sodass Du @RemodifyBerlin die Möglichkeit hast, Deinen PR eventuell noch anzupassen und Deine an sich sehr guten Ansätze in das Projekt integrieren zu können.

Die Lösung baisert dabei auf Zeebe, der Cloud-nativen, eventgesteuerten Lösung von Camunda (https://camunda.com/de/platform/zeebe/) und der Dokumentation von diesem (https://docs.quarkiverse.io/quarkus-zeebe/dev/index.html):

Zuerst muss in der pom.xml folgende Dependency hinzugefügt werden:

<dependency>
            <groupId>io.quarkiverse.zeebe</groupId>
            <artifactId>quarkus-zeebe</artifactId>
            <version>1.6.0</version>
        </dependency>

Diese Dependency fügt den Zeebie-Client, sowie den Worker hinzu und bietet die Möglichkeit innerhalb des Codes BPMN auszuführen. Damit eine Verbindung zum Zeebe-Worker hergestellt werden kann, muss im nächsten Schritt ein Zeebe-Container mithilfe der Docker-Compose deployed werden:

  zeebe:
    image: camunda/zeebe:latest
    ports:
      - "26500:26500" # gRPC-Port für Client-Verbindungen
    environment:
      - ZEEBE_BROKER_CLUSTER_SIZE=1
      - ZEEBE_BROKER_PARTITIONS_COUNT=1
      - ZEEBE_BROKER_REPLICATION_FACTOR=1

Folgende properties wurden aus dem oben erwähnten Tutorial übernommen und sollten eventuell angepasst werden:

quarkus.zeebe.resources.enabled=true
quarkus.zeebe.resources.location=bpmn
quarkus.zeebe.devservices.enabled=true
quarkus.zeebe.devservices.shared=true
quarkus.zeebe.devservices.service-name=zeebe_broker
quarkus.zeebe.devservices.reuse=false
quarkus.zeebe.dev-mode.watch-bpmn-dir=true
quarkus.zeebe.dev-mode.watch-bpmn-files=true
quarkus.zeebe.dev-mode.watch-job-worker=true

Diese Einstellungen sorgen dafür, dass die im src/main/ressources/bpmn befindlichen bpmn Dateien automatisch in Zeebe deployed werden.
Innerhalb dieses Ordners können nun also entsprechende BPMN-Files abgelegt werden. Als einfache Demonstration habe ich mich hier für folgendes BPMN entschieden:

image

Hierbei ist vor allem die id der einzelnen Tasks wichtig, da diese später für die JobWorker benötigt werden. Die Ids können entweder in der XML direkt gefunden werden (bpmn:process id="id") oder im Modeller gesetzt werden.

Um den Workflow nun starten zu können, reicht ein einfacher Controller:

package de.remsfal.service.control;

import io.camunda.zeebe.client.ZeebeClient;
import jakarta.inject.Inject;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

import java.util.Map;

@Path("/zeebe")
public class ZeebeController {

    @Inject
    ZeebeClient zeebeClient;

    @Path("/start")
    public String startWorkflow(@QueryParam("decision") String decision) {

        Map<String, Object> variables = Map.of("decision", decision);

        var workflowInstance = zeebeClient.newCreateInstanceCommand()
                .bpmnProcessId("decisionProcess")
                .latestVersion()
                .variables(variables)
                .send()
                .join();

        return "Workflow instance started with key: " + workflowInstance.getProcessInstanceKey();

    }
}

Dieser Controller startet nun meinen oben erwähten Beispielworkflow.

Damit der Workflow ordentlich abgearbeitet werden kann, ist es noch notwendig einzelne JobWorker für die entsprechenden Prozessschritte zu definieren:

package de.remsfal.service.zeebe;


import io.camunda.zeebe.client.api.response.ActivatedJob;
import io.camunda.zeebe.client.api.worker.JobClient;
import io.quarkiverse.zeebe.JobWorker;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;


public class ZeebeWorker {

    @Inject
    Logger logger;

    @JobWorker(type = "yesTask")
    public void yesTaskHandler(final JobClient client, final ActivatedJob job) {
        logger.info("Yes task handler called");
        client.newCompleteCommand(job.getKey()).send().join();
    }

    @JobWorker(type = "noTask")
    public void noTaskHandler(final JobClient client, final ActivatedJob job) {
        logger.info("No task handler called");
        client.newCompleteCommand(job.getKey()).send().join();
    }

}

Mithilfe dieses einfachen Setups ist es möglich eine Workflow-Engine zu integrieren.

Wenn Du das entsprechend für Deinen Ticketworkflow anpasst, kann auch eine Integration in das Projekt erfolgen

@RemodifyBerlin
Copy link
Contributor Author

@gflachs @astanik Thank you both for the thorough review and the helpful references! I was too focused on getting Camunda 7 working with Quarkus that I overlooked the possibility of integrating with Zeebe.

I really appreciate you pointing me in that direction and providing the test setup. Before this, I wasn’t aware of Zeebe at all, so that was a great learning experience. I believe this update should now meet all the requirements. Thanks again for pointing me in the right direction!

@RemodifyBerlin
Copy link
Contributor Author

@gflachs @astanik Could you please review it one more time so I have enough time to make any necessary adjustments before the deadline?

@gflachs
Copy link
Contributor

gflachs commented Jan 6, 2025

@gflachs @astanik Could you please review it one more time so I have enough time to make any necessary adjustments before the deadline?

@astanik Ich bräuchte bitte nochmal das Recht zu reviewen, ich kann aktuell kein Review hinterlassen

@astanik astanik requested a review from gflachs January 6, 2025 12:58
Copy link
Contributor

@gflachs gflachs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vielen Dank für das Umsetzen des Feedbacks. Die JobWorker könnten noch generischer gestaltet werden (z.B. einen generellen JobWorker für das prüfen von approvals etc.), es ist aber ein erster guter Ansatz. Allerdings fehlen mir hier noch die im Issue beschrieben Schritte des Workflows:

Bei Bedarf werden Rückfragen oder zusätzliche Informationen im Prozess berücksichtigt. (Entscheidungsgateway)
3A Der zuständige Mitarbeiter anwortet
3B Es wird zum Endtask navigiert
Abschluss:
Das Ticket wird als gelöst markiert, und der Kunde oder das Team wird informiert.

Diese sollten noch implementiert werden

…d enhance error handling; update README with usage examples and add unit tests for controller
@RemodifyBerlin RemodifyBerlin force-pushed the #267-implement-camunda-docker-container-with-task-workers branch from a3fcc47 to 53defdb Compare January 7, 2025 14:35
@RemodifyBerlin
Copy link
Contributor Author

RemodifyBerlin commented Jan 7, 2025

@gflachs Danke für dein Review!

Die genannten Punkte wurden soweit umgesetzt. Zu deinem Punkt: „(...) Diese Schritte sollten noch implementiert werden.“ – Der erste Prozess war ein initiales Konzept, das eine Entscheidung und Variablen beinhaltet. Ziel war es, einen einfachen Prozess darzustellen, der eine Entscheidung und Variable umfasst. Dies gilt sowohl für den neuen Prozess als auch für den initialen Prozess.

Für das erste Konzept wäre es erforderlich gewesen, unnötige Logik zu simulieren, was nicht zielführend war. Deshalb habe ich es in einen Ticket-Prozess umgewandelt, bei dem ein Mitarbeiter über den Ticket-Prozess entscheidet und Variablen festlegt, sodass die Zeebe-Funktionen gezeigt werden. So werden die Grundfunktionen von Zeebe präsentiert. Der Prozess oder die Bezeichnungen der Schritte machen dabei keinen Unterschied.

Ich hoffe, es passt! Lass mich wissen, falls du weitere Anmerkungen hast.

Copy link
Contributor

@astanik astanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pioneering achievement in terms of processing in remstal. Feel free to create issues for my review points.

*/
class ZeebeControllerTest {

@Mock
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main logic is mocked, may be because devservices are not enabled while testing.

requestBody.put("variables", Map.of("var1", "value1"));

// Act
Response response = controller.startWorkflow(requestBody);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an integration test and the REST API with its authentication have not been tested.

@@ -0,0 +1,41 @@
package de.remsfal.service.zeebe;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zeebe worker should be part of the control layer.

import java.util.Map;
import org.jboss.logging.Logger;

@Path("/zeebe")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The REST API should be in the boundary layer.


@POST
@Path("/start")
public Response startWorkflow(Map<String, Object> requestBody) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be much more readable if the json body was implemented as a java class, e.g. remsfal-core/src/main/java/de/remsfal/core/json/**/*Json.java

@astanik astanik merged commit 03073a2 into remsfal:main Jan 8, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request ready for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implementierung einer Workflow-Engine in das Projekt
3 participants