Integracja aplikacji z Camunda BPM

Camunda została założona przez Jakoba Freunda i Bernda Rückera w 2008 roku jako firma konsultingowa w zakresie zarządzania procesami biznesowymi (BPM).  Camunda utworzyła własną wersję projektu Activiti,  Camunda BPM jako projekt open-source. Intencją było stworzenie produkty doskonalszego, lżejszego, prostszego w użyciu i bardziej wydajnego. I to się udało. Camunde możemy zakupić jako serwis "cloud" lub zainstalować on premise - we własnej infrastrukturze.

Czym jest Camuda? W artykule na naszym blogu możesz przeczytać (i zacznij od tego) czym jest BPMN i jaka jest rola platform BPM. Zanim zaczniesz testy z Camundą, bardzo ważne jest zrozumienie jaką rolę pełni platforma BPM, w tym Camunda. Funkcję takich plaftorm możemy porównać do poczty lub firm kurierskich. Dostarczają oni wiadomości od adresatów do odbiorców.

Poprawnie zaimplementowana platforma najczęściej nie wykonuje zadań w połączonych z nią systemach, nie zarządza ani nie przesyła danych. Jej rolą jest tylko poinformowanie uczestników procesu że należy wykonać jakąś czynność i odebranie informacji że czynność ta została wykonana. Następnie przesłanie informacji dalej - do następnego uczestnika procesu. Camunda organizuje pracę, za jej pomocą można analizować proces (wydajność, czas, koszt...) itd.

Na stronie Camunda możemy znaleźć opis "Nasza platforma automatyzacji procesów umożliwia dziesiątkom tysięcy programistów projektowanie, automatyzację i ulepszanie procesów oraz zapewnianie lepszej obsługi klientów, szybsze realizowanie projektów i zwiększanie sprawności biznesowej". Same jednak reguły BPM niczego nie automatyzują. Ale ponieważ organizują przepływ informacji, a prowadzenie biznesu to w dużej części przekazywanie właściwych informacji/decyzji do właściwych ośrodków, sygnalizują właściwym systemom/osobom konieczność wykonania właściwej operacji.

Platformy BPM często dają możliwość zbudowania aplikacji na podstawie diagramu procesu. Np. gdybyśmy chcieli zbudować proces akceptacji zaliczek na wyjazdy służbowe, moglibyśmy stworzyć ten proces z użyciem BPMN a następnie opublikować na platormie która automatycznie stworzyłaby potrzebne formularze, interfejsy dla uczestników takiego procesu. Gotowa aplikacja webowa. Choć taka perspektywa jest kusząca, zdecydowanie lepiej jest podzielić ten schemat działania na dwie warstwy; platforma BPM zarządza logiką biznesową, front-end dla użytkownika zbudować w innym narzędziu które będzie bardziej zaawansowane (aplikacje platform BPM to proste, automatycznie generowane strony) i jednocześnie nie uzależni nas od jednego dostawcy.

Pakiet Camunda - jakie produkty oferuje Camunda

Jak większość producentów produktów klasy BPM, Camunda oferuje Modeler i BPMN Workflow Engine ("platformę"). W modelerze rysujemy proces - diagram procesu. Jest to graficzna interpretacja procesu. Czasami możemy na tym poprzestać; większość diagramów powstaje by po prostu zobrazować proces, sprawdzić logikę procesu - jeśli coś nie układa się na rysunku, nie będzie też działać w rzeczywistości.

BPMN Workflow Engine to oprogramowanie które możemy zainstalować na serwerze lub używać gotowego rozwiązania "w chmurze". Diagram procesu który wcześniej stworzyliśmy w Modelerze, publikujemy tam właśnie. Po opublikowaniu definicji procesu (diagramu) możemy uruchamiać instancje procesu. Każde uruchomienie procesu poprzez wysłanie danych do rezydującej na platformie definicji procesu powoduje uruchomienie kolejnej instancji procesu. Np proces ktory obsługuje akceptacje wydatków (patrz niżej) - aplikacja wysyła do platformy BPM informację że należy zaakceptować wydatek w kwocie XX dla działu ZZ. Aplikacja "nie wie" kto zaakceptuje ten wydatek, ile poziomów akceptacji będzie to wymagać, co ma się stać z nie zaakceptowanymi na czas wydatkami. Tym wszystkim będzie sterowac proces w Camunda. Aplikacja wysyła zadanie do Camundy i otrzyma rezultat pracy (a raczej informacje o wykonanej pracy).

Prosty przykład użyciaCamundy - akceptacja wydatków, tworzymy diagram BPMN

Nic tak dobrze nie pozwoli Ci zrozumieć roli BPM i poznać co możesz zrobić z pomocą Camundy jak przejscie przez ćwiczenie w ktorym stworzymy diagram prostego procesu a następnie będziemy komunikować się z tym procesem inicjując go (czyli wysyłając do niego zadanie), pobierajac zadania i oznaczać realizację wykonania zadań.

Naszym procesem jest proces akceptacji faktruy. Jak widzisz poniżej, proces posiada dwa poziomy akceptacji faktur.

Diagram takiego procesu tworzysz w Camunda Modeler. Nie będziemy tutaj opisywać kroków które należy wykonać by zainstalować zarówno Modeler jak i Platformy Camunda - ich instalacja do celów testowych jest prosta i sprowadza się praktycznie do pobrania plikow ze strony Camunda, ich rozpakowania i uruchomienia programów.

Proces musi posiadać swoj ID po którym będzie identyfikowany na platformie. Zaczynając rysować nowy diagram, wejdź do ustawień proceu, General => Process ID, i nadaj mu unikalny ID. Jak w każdym programie, tak i w procesie BPM ważne są zmienne dzięki którym logika procesu BPM będzie wiedzieć jak pokierować taskami. We właściwościach procesu znajdziesz zakładkę 'Variables'. Jednak zobaczysz że nie można tam wstawić żadne zmiennej. Dlaczego?

W Camunda zmienne tworzy się dynamicznie. To bardzo ważne by to zrozumieć. Model procesu nie zawiera na stałe przypisanych zmiennych. Możesz jest utowrzyć w momencie inicjowania procesu, możesz je dodać lub uzupełnić w momencie obsługi tasku. Na początku wydaje się to dziwne ale szybko zrozumiesz jak wielką swobodę daje Ci to w obsłudze procesów w Camunda. Utworzmy więc taski naszego procesu. Poniżej znajdziesz obraz właściwości pierwszego zadania - 'Akceptacja poziom 1'.

 

Każdy task, tak jak proces, ma swój ID. Będziemy odwoływać się do niego właśnie używając ID nie jego nazwy. Nazwa jest tylko dodatkowym uzupełnieniem. Następnym obiektem po pierwszym tasku, jest to 'manual task' co ważne, jest bramka (gateway). Bramki często mylnie są nazywane "punktami decyzyjnymi". Naprawdę są do elementy które sterują procesem - nie zawsze tylko jedna scieżka jest wybierana albo są używane do łączenia przepływów. Strzałka między taskiem "Akceptacja poziom 1" a bramką to "przepływ" (flow). W tym procesie nie jest ważne jak się nazywa ani jaki jest jego ID. Dostarcza wszystkie zmienne do bramki. Sama bramka także może pozostać z domyślnym ID i nazwą.

Przepływy od bramki "Exclusive gateway" (X) muszą natomiast mieć wyrażenia by odpowiednio pokierować przepływem komunikatów. I tak np. przepływ od bramki do tasku "Akceptacja poziom 2" ma wyrażenie '${approved && level == 2}' czyli kieruj tu wszystko gdzie zmienna 'approved' ma wartość true i zmienna 'level' ma wartość 2.

Przepływ 'Nie zaakceptowana' będzie mieć wyrażenie '${!approved}'. ID tych flows nie ma większego znaczenia dla naszego ćwiczenia. Muszą być unikalne i nadaj im logiczne oznaczenia.

By wyrażenia te zadziałały, przy inicjowaniu procesu (wysyłaniu komunikatu do procesu o konieczności akceptacji faktury) wyślemy zmienną 'level = 1' dla jednych faktur i 'level = 2' dla innych (np. w zależności od kwoty. W procesie produkcyjnym lepiej poprzedzic "Akceptacja poziom 1' taskiem typu 'Business Rule' (DMN diagram) który zadecyduje czy faktura ma byc akceptowana przez dwa czy jeden poziom i utworzy zmienna 'level' ale o tym w innym poscie na blogu. Wyrażenia dla przepływu 'Zaakceptowana' (od bramki do konca procesu) to '${approved && level == 1}', akceptacja drugiego poziomu to wyrażenie '${approved}' a dla obu poziomów odrzucenie do po prostu '${!approved}'.

Publikujemy diagram BPMN na platformie Camunda BPM

Uruchom Camunda Platform i zaloguj sie do niej (domyślne hasło/login 'demo/demo'). Jeśli to jest Twój pierwszy kontakt z tym systemem - możesz być lekko rozczarowany. Trochę nie intuicyjne i proste menu. Z pewnością zastanawiasz się teraz "OK, mam diagram procesu - jak to teraz opublikować". Nie znajdziesz takiego menu. Jest niedostępne w wersji community Camundy.

Ekran Camunda Platform po zalogowaniu się.

Możesz umieścić proces który zrobiliśmy powyżej na platformie używając Modeler'a. W pasku narzędzi znajdziesz przycisk 'Deploy current diagram'. Domyślnie pole 'REST endpoint' będzie wskazywać na adres platformy na Twoim komputerze. Pozostawiasz domyślne ustawienia i klikasz 'Deploy'. Możesz następnie uruchomić proces klikając przycisk obok 'Start current diagram'. Spowoduje to inicjacje procesu czyli wyslanie sygnalu do platformy by rozpoczeła akceptację faktury - pierwszy task 'Akceptacja poziom 1' otrzyma oczekujące na wykonanie zadanie.

Powiedzieliśmy że menu Camunda Platform (w wersji darmowej) jest proste. Jednak możesz zrealizować dużo więcej używając REST. Camunda ma bardzo rozbudowane REST i to jest super wiadomość ponieważ możemy zintegrować praktycznie każdy system, każdą aplikację z Camundą - warstwa komunikacji jest niezależna od języka systemu. Dużym minusem są odpowiedzi REST - często komunikaty są zupełnie nieadekwantne do zdarzeń. Metody rest akceptują też np POST choć powinny tylko GET a co więcej zwracają rezultaty ...losowe. Jednak poprawnie użyte są stabilne i wykonują swoją robotę.

W naszych testach by komunikować się z REST Camundy użyjemy Postman. Pobierz ten program, uruchom, stwórz 'Nową kolekcję' a w niej 'Nowe żądanie'. Tworzymy request który użyje metody REST 'deployment/create'.

POST http://localhost:8080/engine-rest/deployment/create
Headers: Content-Type, multipart/form-data
Body:
Key, upload
Value, wybierz plik diagramu

Wykonaj to żądanie REST. Jeśli wszystko poszło poprawnie, definicja procesu została umieszczona na platformie. Możesz załadować tę samą definicję wiele razy - będą to kolejne iteracje definicji. OK, mamy umieszczoną definicję procesu. Jeśli chcesz usunąć wysłaną definicję procesu, wykonujesz metodę DELETE http://localhost:8080/engine-rest/process-definition/id_procesu?cascade=true Parametr 'cascade' zapewnia usunięcie wszystkich tasków w procesie. Bez tej opcji niemożliwe jest skasowanie definicji procesu jeśli w procesie znajdują się otwarte taski.

W menu platformy, http://localhost:8080/camunda/app/cockpit, masz widok który pokazuje ilość definicji procesu, ilość 'Decisions Definistions' (reguł biznesowych), ilość tasków itd.

Kliknij na cyfre pod 'Process Definitions'. Wyświetli się lista definicji procesów. Nasz proces jest na tej liście. Kliknij na niego. Widzisz czysty diagram i pustą listę "Process instances". Pora zainicjować proces - wysłać pierwsze zadanie do procesu.

Inicjujemy proces na platformie Camunda

Inicjujemy proces czyli wysyłamy informację do definicji procesu. Użyjemy 'process-definition/key/process_id/start':

POST http://localhost:8080/engine-rest/process-definition/key/invoice-approval-test-v0/start
Headers: Content-Type, application/json
Body: raw
{
  "variables": {
    "level" : {
        "value" : 1,
        "type""Double"
    }
  }
}

Mówiliśmy o tym wcześniej. Mapę zmiennych tworzymy w Camunda dynamicznie. Tutaj zainicjowaliśmy proces. Definicja procesu będzie potrzebować zmiennej by przesłać zadanie akceptacji do jednego lub dwóch poziomów akceptacji. Zatem przesłaliśmy wraz z utworzeniem instancji procesu zmienną 'level'. Ale tę zmienną moglibyśmy też dodać w momencie wykonywania tasku - patrz niżej. Odświeżając teraz ekran Camundy w przeglądarce, zobaczysz że kółeczko z jedynka (ilość "running activity instances") przy tasku 'Akceptacja poziom 1' - w tym tasku utworzył się... task do obsługi przez uczestnika procesu. Niżej, w liście "process instances" mamy ID tej instancji i jeśli klikniemy na nie, otrzymamy listę zmiennych przypisanych do tasku.

Odczyt tasków w Camunda - budujemy task listę

Proces BPM skłąda się z szeregu tasków i przepływów między nimi. Tym przepływem steruje platforma BPM.  Zewnętrzne systemy czytają taski i tworzą tasklisty (czytają zadania i tworzą listy zadań). Najczęstszą praktyką jest że aplikacja która współpracuje z Camundą odczytuje listę zadań w tasku X, i wyświetla ją dla użytkowników którzy zajmują się obsługą tych zadań. To samo dzieje się z taskiem Y który ktorego zadania trafiają w formie tasklisty do użytkowników Y. Użytkownicy następnie pobierają te zadania (każde zadanie powinno mieć swojego właściciela - to jest najlepsza praktyka) i po wykonaniu pracy informują Camundę że je zrealizowali; robią "task complete". Gdyby taski były rodzaju 'Service task', wykonaniem zadań znajdujących się na taskliście utworzonej z odczytu znajdujących się tam zadań zająłby się zewnętrzny proces/program. Tak samo jak w przypadku 'manual task', po wykonaniu zadania zwraca informację do Camunda - 'zrobiłem to zadanie'. W zdecydowanej więszości przypadków Camunda NIE POWINNA wykonywać pracy w zewnątrznych systemach. Ma im tylko dostarczyć informację że coś należy zrobić. To samo z danymi. Transmisja danych, operacje na danych powinny być wykonywane przez zewnętrzne systemy. OK, budujemy tasklistę - odczytamy wszystko z tasku o ID 'approve_l1' (Akceptacja poziom 1).

GET http://localhost:8080/engine-rest/task?taskDefinitionKey=approve_l1

W rezultacie otrzymamy listę tasków ze szczegółami:

[
    {
        "id""008c54d4-9e9e-11eb-88ae-049226bdb658",
        "name""Akceptacja poziom 1",
        "assignee"null,
        "created""2021-04-16T12:25:01.615+0200",
        "due"null,
        "followUp"null,
        "delegationState"null,
        "description"null,
        "executionId""008aa71f-9e9e-11eb-88ae-049226bdb658",
        "owner"null,
        "parentTaskId"null,
        "priority"50,
        "processDefinitionId""invoice-approval-test-v0:1:a5f0729a-9e9b-11eb-88ae-049226bdb658",
        "processInstanceId""008aa71f-9e9e-11eb-88ae-049226bdb658",
        "taskDefinitionKey""approve_l1",
        "caseExecutionId"null,
        "caseInstanceId"null,
        "caseDefinitionId"null,
        "suspended"false,
        "formKey""10",
        "tenantId"null
    }
]

Wykonanie tej metody jest nam potrzebne nie tylko dlatego by sprawdzić czy coś oczekuje w tasku o ID 'approve_l1' ale by też by pobrać ID znajdujących się tam aktywności. Kiedy inicjujesz proces, patrz poprzedni krok, otrzymujesz ID tej instancji procesu. Nie jest to jednak ID taksku ktory uzyskamy po odczytaniu zadań z tasku 'approve_l1'. Nie znamy tych ID w momencie inicjacji procesu. Dlaczego? Proces może się rozwidlać. Np. wyobraź sobie wniosek o zatrudnienie pracownika. Po zarejestrowaniu nowego pracownika mogą powstać zadania dla IT przygotowania sprzętu, dla menagera floty o wydanie samochodu służbowego, dla BHP o przeprowadzenie szkolenia. W ten sposób zrobiły nam się trzy niezależne taski (nie wiedzieliśmy tego inicjując proces). Mogą one powstawać nawet w różnych okresie czasowym. Dlatego budując tasklistę odczytujemy ID znajdujących się tam tasków.

Odczytujemy zmienne tasku

Ten punkt możesz pominąć jeśli nie potrzebujesz odczytywać wartości zmiennych. Najczęściej jednak będziesz tego potrzebować. Jeśli wysyłałeś z jakiegoś systemu informacje do Camundy by uczestnicy procesu zaakceptowali (lub odrzucili) fakturę, dobrze byłoby fakt akceptacji odnotować w systemie lub śledzić stan akceptacji (jeśli będzie to więcej niż jeden poziom). Zatem inicjując proces możemy umieścić tam np. zmienną 'row_id' (numer rekordu w bazie danych). Camunda nie oferuje metody która odczyta listę tasków wraz ze zmiennymi. Znając ID tasku, wykonujemy następną metodę by odczytać przypisane do niego zmienne:

GET http://localhost:8080/engine-rest/task/008c54d4-9e9e-11eb-88ae-049226bdb658/variables

W rezultacie otrzymamy JSON zawierający nazwę zmiennych, ich typy oraz wartości.

Oznaczamy task jako wykonany - complete task

Użytkownik aplikacji klika na przycisk 'akceptuj fakturę' i aplikacja wysyła do REST informację używając metody 'task/task_id/complete':

POST http://localhost:8080/engine-rest/task/008c54d4-9e9e-11eb-88ae-049226bdb658/complete
Headers: Content-Type, application/json
Body: Raw

{
  "variables": {
    "approved" : {
      "value" : true,
      "type": "Boolean"
    }
  }
}

Camunda wykona żądanie, zwróci kod 204. Ponieważ ta faktura wymagała tylko jednego poziomu walidacji, po odświeżeniu diagramu procesu w przeglądarce (kokpit) zobaczysz że proces nie ma już żadnych działających instancji. Camunda zrobiła swoje. Aplikacja otrzymała wszystkie niezbędne inforamcje z Camundy by w momencie kiedy wysyła do BPM informacje "użytkownik zaakceptował fakturę", jednocześnie oznaczyła odpowiednio dane faktury w zewnętrznym systemie (poza Camundą). Zauważ że diagram procesu, ustawienia tasku posiada zakładkę "forms". Możesz tam umieścić informację jaki formularz lub/i jakie moduły potrzebne są w aplikacji by obsłużyć taki task. To pole typy String więc masz dużą swobodę co tam wpiszesz. Możliwa jest nawet definicja pól jakie powinien posiadać formularz obsługi tasku.

Co dzieje się z informacją o taskach po zakończeniu procesu?

Rola Camundy kończy się wraz z zakończeniem procesu. Od tej pory nie ma żadnych relacji między aplikacją a platformą BPM. Informacje te są przechowywane przez pewien czas w tabelach bazy Camundy dla celów audytowych po czym są usuwane. Jednak jako projektant procesu masz wpływ jak długo one mają one oczekiwać na zajęcie się nimi w taskach i jak długo mają być przechowywane dla celów audytu po zakończeniu procesu. Na poziomie tasku możesz żąglować parametrami 'Due date' oraz 'Follow Up Date'. Na poziomie procesu masz parametr 'History Time To Live' który określa jak długo informacje po zakończeniu procesu pozostaną w tabelach bazy Camunda.