Я много общаюсь о микросервисных архитектурах с «не-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 и 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.

Комментарии (8)


  1. olku
    17.06.2025 17:09

    По какой-то причине есть люди, считающие что BPMN это zero code. Нарисовал, сохранил XML и оно заработало. Но в реальности разработчику приходится иметь дело и с бизнес процессом, куда он погружаться не хочет, и с кодом одновременно.


    1. stas_makarov Автор
      17.06.2025 17:09

      Ну да, матчасть (нотацию) надо учить.
      Как и любой другой инструмент.
      А то бывает разработчики такого лепят на BPMN, что кровь из глаз.
      Да, это не интуитивно понятно - вроде квадратики-стрелочки, ан нет.
      но кому сейчас легко?


      1. olku
        17.06.2025 17:09

        Ваш комментарий перечеркнул посыл статьи. :)

        Есть два типа стейкхолдеров. Продуктовые знают Что, но не знают Как. Инженерные знают Как но не знают Что. Ни первые ни вторые не любят погружаться в домены друг друга. Отсюда вывод - инструменты, требующие оба сразу - не удобные и не простые, как их пытаются представить. Красивая игрушка для руководства в энтерпрайз, где могут себе позволить. В конторах попроще встречал лишь как слайды презентаций заказчикам. Поправьте, если что.


        1. ayrtonSK
          17.06.2025 17:09

          В точку. Поэтому необходимо сделать так, чтобы продуктовые ничего не писали на каких либо языках, а оперировали лишь бизнес смыслом и переменными, а разработчики реализовывали на своём языке сервис таски как юнит тесты. Иначе будет как вы написали. Нам эту модель до конца ещё не удалось воплотить, пока ещё разработчики дебажат bpmn, но если контракт для ServiceTask/UserTask полностью декларировать в камунде, то тогда открывается возможность разработчику вообще не открывать камунду. Правда тогда именно продуктовики будут дебажить, но они уже это делают. Вам спасибо, за меткое разделение стейкхолдеров.


          1. olku
            17.06.2025 17:09

            Да не за что. Если получится, то ждём статью. Противоречие не решаемо десятилетиями. Не зря Камунде придумали альтернативны code first. Клиенту нарисуем за его деньги любые нужные ему картинки, а работать будем как нужно нам.


            1. ayrtonSK
              17.06.2025 17:09

              У себя в LowCode платформе мы вначале делаем контекст домена, рисуем модель, а только потом на этих понятиях делаем BPMN для заказчика первую версию, но именно "за его деньги любые нужные ему картинки" а потом определенным образом превращаем в ServiceTaskи по клику и несколько итераций по приведению bpmn в реальный вид. В одной из своих прошлых LowCode платформ был даже свой движок BPMN, который не по нотации, но ближе к делу, так как контекст был не из дурацких переменных камунды, а нормальной ООП модели домена, это гораздо интереснее, но есть серьезный минус.


        1. stas_makarov Автор
          17.06.2025 17:09

          Да, проблема существует.
          Но правда в том, что ни аналитики, ни разработчики толком не знают нотацию.
          Правда, не знают ее по-разному.
          Однако, есть пересечение, пусть и небольшое.
          Окей, будем просвещать. Gutta cavat lapidem. Вроде так говорили.
          Люди, которые придумывали нотацию, верили, что это будет общий язык технарей и бизнеса. Пока не случилось. Некоторые вещи доходят медленно.
          Из моей практики -- если человеку объяснять, обычно он понимает.
          Вот, например, такая классная вещь, как компенсации.
          Вообще никто не шарит, ни айтишники, ни бизнес.


  1. ayrtonSK
    17.06.2025 17:09

    Спасибо за подсказку, что есть (Pull-принцип) , не знал этого.