Процесс — это код
Условия шлюзов, скрипты и таблицы DMN генерируются в Go-функции до запуска. Нет интерпретатора
выражений в рантайме: условие шлюза — обычный if.
Стрелки — выбор, Enter — открыть, Esc — закрыть
Открытый код · Go · PostgreSQL
go-bpm превращает схемы BPMN и таблицы DMN в типизированный Go-код и исполняет его
на очереди задач в PostgreSQL — в той же базе, что и данные сервиса. Отдельного сервера процессов нет:
движок — библиотека внутри вашего сервиса. Методы и решения проверяются обычным go test.
Проверено на Astra Linux Special Edition 1.8.1.6 →
$ go get github.com/nicolas-vp/go-bpm
func CheckOrder(ctx context.Context, svc *services.Services,
data *model.DataModel) error {
if data.Amount <= 0 {
return fmt.Errorf("сумма должна быть положительной")
}
data.Checked = true
return nil
}
Моделер, генерация кода, шаг в одной транзакции, скорость и история экземпляра в консоли — коротко обо всём, что подробнее ниже на странице.
В go-bpm modeler — своём редакторе: в палитре только то, что исполнит go-bpm,
схема проверяется правилами генератора. Схемы из Camunda Modeler тоже подходят: go-bpm читает
расширения gobpm:* и zeebe:*. Схемы BPMN и таблицы DMN лежат
в process/ репозитория сервиса и проходят ревью вместе с кодом.
go-bpm-gen проверяет схему и создаёт Go: переходы, условия шлюзов, скрипты, решения DMN
и заготовки ваших методов. Опечатку в условии покажет компилятор.
Движок исполняет процесс на очереди задач в PostgreSQL. Каждый шаг — задача очереди, все его эффекты пишутся одной транзакцией.
Условия шлюзов, скрипты и таблицы DMN генерируются в Go-функции до запуска. Нет интерпретатора
выражений в рантайме: условие шлюза — обычный if.
Переход токена, история и новые задачи пишутся вместе с завершением задачи очереди. Упал сервис посередине — шаг повторится целиком, токен не потеряется и не раздвоится.
Переменные процесса читаются в вашу DataModel. Методы работают с полями, а не
с map[string]any.
Очередь, история, экземпляры и задачи пользователей — таблицы bpm_* в вашей базе.
Сервис масштабируется несколькими экземплярами на одной базе.
StartProcessTx запускает процесс в той же транзакции, где сервис пишет свои данные:
заказ и его процесс появятся вместе или не появятся вовсе.
/ui/: процессы, запуск, поиск экземпляров, задачи пользователей, история экземпляра
поверх диаграммы bpmn-js со сработавшими правилами DMN, термокарта и динамика процесса.
Тестирование
go testЛогика процесса — это ваши Go-функции, а не выражения внутри XML. Поэтому её проверяют так же, как остальной код сервиса: без моделера, движка и специального тестового фреймворка.
*model.DataModel
и проверить поля.services.Services: в тесте
подставляются заглушки.decide<Id>, тестируются
из пакета процесса.// internal/bpmgen/order_approval/method_check_order_test.go
func TestCheckOrder(t *testing.T) {
ctx, svc := context.Background(), &services.Services{}
data := &model.DataModel{Amount: 500}
if err := CheckOrder(ctx, svc, data); err != nil {
t.Fatal(err)
}
if !data.Checked {
t.Error("заказ не отмечен проверенным")
}
if err := CheckOrder(ctx, svc, &model.DataModel{}); err == nil {
t.Error("пустой заказ прошёл проверку")
}
}Настройка и расширение
go-bpm — библиотека, а не платформа: движок, API и консоль собираются из частей внутри вашего сервиса, и каждую можно настроить или заменить своей.
Клиенты баз, API и очередей — поля services.Services. Они доступны во всех методах
и обработчиках, а типы проверяет компилятор.
Переменные процесса — поля вашей DataModel, включая вложенные структуры. Генератор
подскажет, каких полей не хватает.
Генератор создаёт заготовки методов, обработчиков и модели один раз и больше их не трогает.
Пересоздаются только файлы с пометкой Code generated by go-bpm-gen.
API и консоль — обычные обработчики на вашем http.ServeMux. Подключайте только то,
что нужно, и закрывайте своим middleware.
migrations.Up применяет схему сам, а для goose, migrate или liquibase SQL берётся
из migrations.List().
Воркеры, попытки, таймауты и задержки повторов, логгер slog, история с флагами,
которые переключаются на лету, и префикс очереди для версий процессов.
metrics.Collector регистрируется в реестре сервиса: очередь по статусам, возраст самой
старой задачи, упавшие экземпляры, открытые задачи пользователей, время попыток.
engine.Hooks: события элементов, обёртка вокруг вызова вашего кода — место для span
OpenTelemetry — и падение экземпляра, чтобы поднять алерт.
engine.Retention удаляет завершённые и отменённые экземпляры старше срока вместе
с историей и задачами. Упавшие не трогает — они ждут разбора.
Генератор проверяет BPMN и отвергает то, что не поддерживается, — на этапе генерации, а не в рантайме.
Движок, API и консоль подключаются к вашему http.ServeMux и пулу pgx.
Где прошёл токен, какие переменные были у каждой задачи, какое правило DMN сработало, а по всем экземплярам — где процесс проводит время.
Сопровождение
Всё это — в консоли /ui/, в HTTP API и в Go-методах: можно встроить
в свои инструменты.
В истории экземпляра — упавшие задачи его и дочерних экземпляров: элемент, попытки, текст ошибки. «Повторить» возвращает задачу в очередь после выкладки исправления, экземпляр и родители снова выполняются.
Если шаг упал на данных, переменные токена открываются JSON-ом: поправьте поле, и задача выполнится с исправленными.
Корневой экземпляр отменяется вместе с дочерними: снимаются задачи очереди, таймеры и открытые задачи
пользователей, статус — cancelled.
Элементы схемы окрашены от бледного к красному по среднему, максимальному или суммарному времени либо числу проходов — за выбранный период запуска экземпляров.
Экземпляры по дням запуска и чем они закончились: завершены, выполняются, упали, отменены. Медиана и p95 длительности завершённых.
GET /instances/{id}/failures, POST /failures/{taskId}/retry,
POST /instances/{id}/cancel, /processes/{name}/heatmap и
/stats; из Go — engine.InstanceOperations.