
Я много общаюсь о микросервисных архитектурах с «не-Java-людьми» — будь то разработчики на C#, энтузиасты Node.JS/JavaScript или GoLang. Все они сталкиваются с необходимостью оркестрации в микросервисной архитектуре — или просто хотят использовать workflow, упорядочивание действий, обработку таймаутов, Saga и компенсации, а также другие полезные возможности.
Open Source BPM-платформа Camunda отлично подходит для этих задач. Ориентированность на разработчиков — один из ключевых принципов продукта, но при изучении документации может показаться, что она рассчитана в основном на Java-разработчиков. Платформа предоставляет множество точек расширения и интеграции, но всё это реализуется на Java. Значит ли это, что другим разработчикам путь закрыт?
Нет! На самом деле, запустить Camunda и работать с ней без знания Java очень просто — архитектуру можно выстроить так, чтобы писать код на любом удобном языке. В этом посте:
рассматривается базовая архитектура,
описывается REST API,
даются рекомендации по существующим клиентским библиотекам для языков, кроме Java,
приводятся примеры с C# и Node.JS,
рассказывается о способах запуска Camunda-сервера (Docker или Tomcat).
Архитектура
Camunda написана на Java и требует для работы JVM. Camunda предоставляет REST API, что позволяет писать код на любом языке и просто общаться с Camunda по REST:

В Camunda процессы определяются в BPMN, который по сути является XML-файлом. Его можно графически моделировать с помощью Camunda Modeler.

Подписывайтесь на наш телеграм-канал BPM Developers — про бизнес-процессы: новости, гайды, полезная информация и юмор.
Запуск Camunda из готового Docker-образа
Самый простой способ запустить Camunda — использовать Docker. Другие варианты описаны далее в статье.

В простейшем случае достаточно выполнить:
docker run -d -p 8080:8080 camunda/camunda-bpm-platform:latest
Не нужно заботиться о Linux, JVM или Tomcat. Dockerfile и документация (например, как подключить нужную БД) доступны на Github:
camunda/docker-camunda-bpm-platform
docker-camunda-bpm-platform — Docker images for the camunda BPM platform
github.com
Если вы хотите использовать Camunda Enterprise Edition, достаточно изменить Dockerfile для загрузки enterprise-версии:
https://github.com/camunda/docker-camunda-bpm-platform/blob/master/Dockerfile#L26.
Минус такого подхода: вы получаете Tomcat-версию, распространяемую Camunda, которая может не содержать самых свежих патчей. Можно собрать образ самостоятельно на нужной версии Tomcat или воспользоваться другими альтернативами, описанными ниже.
Деплой модели процесса
Рассмотрим пример с классической Saga бронирования путешествия, где нужно вызвать три действия поочерёдно — и при ошибке корректно компенсировать уже выполненные шаги. В BPMN это выглядит так:

Теперь можно использовать REST API для деплоя модели процесса. Предположим, вы сохранили её как trip.bpmn и запустили Camunda через Docker на localhost:8080:
curl -w "\n" \
-H "Accept: application/json" \
-F "deployment-name=trip" \
-F "enable-duplicate-filtering=true" \
-F "deploy-changed-only=true" \
-F "trip.bpmn=@trip.bpmn" \
http://localhost:8080/engine-rest/deployment/create
Теперь можно запускать новые экземпляры процесса через REST API и передавать нужные переменные:
Теперь следующий интересный вопрос: Как Camunda вызывает сервисы, например, бронирование машины? Camunda может вызывать сервисы напрямую (Push-принцип) с помощью встроенных коннекторов, а может помещать задания во внутреннюю очередь. Тогда воркер забирает задания через REST, выполняет работу и сообщает Camunda о завершении (Pull-принцип).

Сначала вы выбираете задачи и блокируете их для себя (другие воркеры могут забирать задачи параллельно для масштабирования):
curl \
-H "Content-Type: application/json" \
-X POST \
-d '{"workerId":"worker123","maxTasks":1,"usePriority":true,"topics":[{"topicName": "reserve-car", "lockDuration": 10000, "variables": ["someData"]}]}' \
http://localhost:8080/engine-rest/external-task/fetchAndLock
Затем сообщаете Camunda, что задача выполнена (нужно указать id задачи, полученный ранее):
curl \
-H "Content-Type: application/json" \
-X POST \
-d '{"workerId":"worker123", "variables": {}}' \
http://localhost:8080/engine-rest/external-task/EXTERNAL_TASK_ID/complete
Подробнее — в документации по External Tasks. Также стоит обратить внимание на вопросы идемпотентности при работе с Camunda через REST.
На этом этапе вы не использовали Java — верно? Этого достаточно, чтобы начать!
Клиентские библиотеки
Вызовы REST API легко делать из любого языка. В JavaScript можно использовать JQuery, в C# — System.Net.Http и Newtonsoft.Json. Но для удобства можно скрыть детали REST за клиентской библиотекой.
На момент написания статьи доступны несколько готовых библиотек:
JavaScript: https://github.com/camunda/camunda-external-task-client-js (официальная поддержка Camunda)
Java: https://github.com/camunda/camunda-external-task-client-java (официальная поддержка Camunda)
C#: https://github.com/berndruecker/camunda-dot-net-showcase и https://github.com/salajlan/camundacsharpclient (проекты неактивны, но могут служить отправной точкой)
PHP: http://camunda.github.io/camunda-bpm-php-sdk/ (неполная поддержка, но используется в некоторых проектах)
Кроме JavaScript и Java, клиентские библиотеки не входят в официальный продукт Camunda. Не ожидайте, что они покрывают весь REST API — если чего-то не хватает, проверьте документацию Camunda REST API. Обычно библиотеки используют как стартовый шаблон.
Пример на C#
Используя указанную выше библиотеку, можно просто написать:
var camunda = new CamundaEngineClient("http://localhost:8080/engine-rest/engine/default/", null, null);
// Deploy the BPMN XML file from the resources
camunda.RepositoryService.Deploy("trip-booking", new List<object> {
FileParameter.FromManifestResource(Assembly.GetExecutingAssembly(), "FlowingTripBookingSaga.Models.FlowingTripBookingSaga.bpmn")
});
// Register workers
registerWorker("reserve-car", externalTask => {
// here you can do the real thing! Like a sysout :-)
Console.WriteLine("Reserving car now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
registerWorker("cancel-car", externalTask => {
Console.WriteLine("Cancelling car now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
registerWorker("book-hotel", externalTask => {
Console.WriteLine("Reserving hotel now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
// Register more workers...
StartPolling();
string processInstanceId = camunda.BpmnWorkflowService.StartProcessInstance("FlowingTripBookingSaga", new Dictionary<string, object>()
{
{"someBookingData", "..." }
});
Полный исходный код доступен онлайн: https://github.com/flowing/flowing-trip-booking-saga-c-sharp. Ещё один пример: https://github.com/berndruecker/camunda-dot-net-showcase.
Пример на Node.js
var Workers = require('camunda-worker-node');
var workers = Workers('http://localhost:8080/engine-rest', {
workerId: 'some-worker-id'
});
workers.registerWorker('reserve-car', [ 'someData' ], function(context, callback) {
var someNewData = context.variables.someData + " - added something";
callback(null, {
variables: {
someNewData: someNewData
}
});
});
workers.shutdown();
Подробнее: https://github.com/nikku/camunda-worker-node
Альтернативные способы запуска Camunda
Кастомный Docker-образ с «Camunda standalone WAR»
Вместо готового Docker-образа Camunda можно подготовить Tomcat самостоятельно (например, на базе официальных образов Tomcat) и скопировать Camunda как war-файл. Пример такого Dockerfile есть в сети.

Если есть дополнительные требования и возможность собрать Java-проект, можно кастомизировать этот war-файл с помощью Maven, как в этих примерах: Maven build reconfiguring the war или Maven build with Overlay.
Запуск дистрибутива Camunda Tomcat
Другой вариант — просто скачать дистрибутив Camunda Tomcat, разархивировать его и запустить. Для этого потребуется только установленная на вашем компьютере Java Runtime Environment (JRE), которую можно легко установить13.

Если вы захотите сменить базу данных или что-то подобное, потребуется настроить Tomcat, как описано в документации. Понимаю, что Tomcat может показаться сложным, но на самом деле всё довольно просто, а любые вопросы легко решаются с помощью Google3.
Запуск Camunda на Tomcat
Ещё один способ — самостоятельно установить Tomcat и развернуть в нём Camunda, следуя инструкции по установке. Это даёт свободу выбрать любую версию Tomcat или, например, установить его как сервис Windows.
Запуск Camunda в продакшн
Обычно перед запуском Camunda требуется финальная настройка. Camunda подробно описывает лучшие практики, но в этом вводном посте я их опущу и приведу только пример: в стандартной сборке REST API не требует аутентификации — это стоит изменить.
Итоги
Как видите, начать работу с Camunda очень просто, независимо от используемого языка. Ключевой момент — всё взаимодействие идёт через REST API. Установка особенно проста при использовании Docker.