07.07.2020 г., перевод статьи Bernd Rcker
Я часто обсуждаю микросервисную архитектуру с людьми, далекими от Java: разработчиками C#, Node.JS/JavaScript или приверженцами Golang. Все они сталкиваются с тем, что им нужен механизм оркестровки в микросервисной архитектуре или просто инструмент для оптимизации рабочего процесса и получения возможности упорядочения, обработки тайм-аутов, Saga и компенсирующих транзакций.
BPM-платформа с открытым исходным кодом от Camunda отлично подходит для таких задач. Дружелюбие по отношению к разработчику одна из ключевых особенностей продукта. Но если взглянуть на его документацию, может сложиться впечатление, что в основном дружелюбие Camunda направлено на Java-разработчиков. Платформа предоставляет множество возможностей для подключения собственных функций и расширений, но все это делается на Java. Так ли это на самом деле?
Нет! На самом деле, можно легко запустить Camunda без каких-либо знаний Java и настроить архитектуру для кода на любом языке, по вашему выбору. В этой статье мы рассмотрим:
- базовую архитектуру;
- REST API;
- советы по существующим клиентским библиотекам для языков, отличных от Java;
- пример использования C # и Node.JS;
- способы запуска сервера Camunda (Docker или Tomcat).
Архитектура
Camunda написана на Java и для запуска нуждается в виртуальной машине Java (JVM). Camunda предоставляет REST API, который позволяет вам писать на любом языке, который вам нравится, и использовать REST с Camunda:
Рабочие процессы в Camunda определяются в BPMN, который в основном представляет собой XML-файл. Его можно смоделировать с помощью Camunda Modeler.
Запуск Camunda через предварительно созданный образ Docker
Самый простой способ запустить Camunda это использовать Docker. Альтернативные способы запуска Camunda описаны далее в этой статье.
В этом случае достаточно просто запустить:
docker run -d -p 8080:8080 camunda/camunda-bpm-platform:latest
Вам не нужно волноваться о Linux, виртуальных машинах Java или Tomcats. Dockerfiles и основная документация (например, инструкция по подключению к нужным базам данных) доступны на Github.
Если вы хотите запустить Camunda Enterprise Edition, вы можете легко изменить Dockerfile.
Однако у запуска Camunda с помощью Docker есть один недостаток: вы получите версию Tomcat, которая не всегда включает последние исправления. Чтобы как-то обойти это, вы можете самостоятельно создать Docker-образ на основе нужного дистрибутива 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/creat
Теперь вы можете запускать новые экземпляры рабочего процесса с помощью REST API и передавать данные, которые вы хотите видеть в качестве переменных экземпляра рабочего процесса:
curl \-H "Content-Type: application/json" \-X POST \-d '{"variables":{"someData" : {"value" : "someValue", "type": "String"}},"businessKey" : "12345"}}' \http://localhost:8080/engine-rest/<!-- -->process-definition/key/<!-- -->FlowingTripBookingSaga<!-- -->/start
Следующий интересный вопрос: как Camunda вызывает процедуры, подобные бронированию автомобиля? Camunda может не только сразу вызывать сервисы (Push-Principle), используя некоторые встроенные коннекторы, но и помещать рабочие элементы в своего рода встроенную очередность. После чего worker может получить рабочие элементы через REST, выполнить работу и сообщить Camunda о завершении (Pull-Principle).
Итак, сначала вам нужно выполнить fetchAndLock (поскольку другие worker могут получать задачи одновременно для масштабирования системы):
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, что worker завершил работу (обратите внимание, что вы должны ввести идентификатор external task, полученный в первом запросе):
curl \-H "Content-Type: application/json" \-X POST \-d <!-- -->'{"workerId":"worker123", "variables": {}}'<!-- --> \http://localhost:8080/engine-rest/<!-- -->external-task/EXTERNAL_TASK_ID/complete
Вот и все вам до сих пор не потребовалось никакой Java, верно? И этого достаточно для начала работы!
Клиентские библиотеки
Вызвать REST API легко в любом языке программирования. В JavaScript это удобно делать с помощью JQuery, а в C# задействовать System.Net.Http и Newtonsoft.Json. Но на это потребуется время. Поэтому вы можете просто воспользоваться какой-нибудь клиентской библиотекой.
На данный момент доступно несколько готовых клиентских библиотек:
- JavaScript: ссылка. Поддерживается Camunda;
- Java: ссылка. Поддерживается Camunda;
- C#:ссылка и ссылка. Оба этих проекта находятся в промежуточном состоянии и практически бездействуют, но могут послужить хорошей отправной точкой;
- PHP: ссылка не слишком полная и не включающая последние изменения API библиотека, но я знаю проекты, использующие её.
За исключением JavaScript и Java, клиентские библиотеки не являются частью самого продукта Camunda. Не ожидайте, что они будут поддерживать все возможности REST API Camunda. Если библиотека не предоставляет определенной функции, это не значит, что ее там нет, всегда проверяйте REST API Camunda. Типовые проекты используют библиотеки в качестве отправной точки и шаблона.
Пример с 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", "..." } });
Полностью рабочий исходный код можно найти в Интернете: ссылка. Другой пример доступен по адресу ссылка.
Пример с 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();
Более подробную информацию можно найти на сайте github.com
Альтернативные способы запуска Camunda
Пользовательский образ Docker с Camunda standalone WAR
В качестве альтернативы готовому образу Docker из Camunda вы можете самостоятельно подготовить Tomcat (например, на основе официальных образов Docker Tomcat), а затем скопировать в него Camunda как один из так называемых WAR-файлов.
Если у вас имеется много дополнительных требовании и вы можете настроить среду сборки Java, вы также можете настроить Camunda Standalone war. Настройте сборку Maven как в этих примерах: сборка Maven с конфигурацией war или сборка Maven с Overlay.
Запуск дистрибутива Camunda Tomcat
Еще один вариант просто скачать дистрибутив Camunda Tomcat, разархивировать его и запустить. Для этого потребуется только Java Runtime Environment (JRE), установленная на вашем компьютере. Её можно легко скачать отсюда.
Чтобы изменить базу данных или сделать что-то еще, вам нужно настроить Tomcat, как описано в документации. Я знаю, что Tomcat может показаться сложным, но на самом деле это очень просто. И Google знает ответы на все, что может потребоваться в процессе.
Запуск Camunda с использованием Tomcat
Последняя альтернатива это самостоятельно настроить Tomcat и установить в него Camunda, следуя описанию установки. Это даст возможность использовать любую версию Tomcat, которую вы предпочитаете, или, например, установить ее в качестве службы Windows.
Запуск Camunda в производство
Как правило, для этого будет необходимо выполнить какие-то окончательные настройки для запуска Camunda. В Camunda есть рекомендации, очень подробно это описывающие, но я не стану затрагивать их в этой статье назову только один пример: REST API дистрибутива по умолчанию не настроен на проверку подлинности. Возможно, вы захотите изменить это.
Подведение итогов
Как вы могли заметить, начать работать с Camunda очень просто, независимо от языка, который вы используете. Ключевой момент состоит в том, что все взаимодействие осуществляется через REST API. Установка тоже довольно проста, особенно при использовании Docker.