dskripchenko / process-engine
Framework-agnostic engine for long-running processes: hierarchical state machines with context, durable execution across days and weeks, external events and timers, explicit retry semantics for every side effect, versioned definitions, a journal and manual operations.
Requires
- php: ^8.2
Requires (Dev)
- laravel/pint: ^1.0
- pestphp/pest: ^3.0 || ^4.0
- phpstan/phpstan: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-27 19:37:58 UTC
README
A framework-agnostic PHP engine for long-running processes: hierarchical state machines (statecharts) with context, durable across days and weeks, waiting on external events and timers, with explicit retry semantics for every side effect, versioned definitions, a journal per instance and operator actions.
- Statecharts with an explicit graph. Nested and parallel states, history, guards, entry/exit/transition actions, choices, child processes. The graph is data: stored per version, drawn by @dskripchenko/flow, checked before it runs.
- Durable by construction. A step is a pure function committed in one transaction (snapshot, journal, outbox). Nothing lives in memory between steps. A crashed worker loses nothing; a duplicate event changes nothing.
- Side effects you can reason about. Every effect declares
#[Idempotent](retried) or#[AtMostOnce](never retried blindly: an ambiguous failure becomesunknown, then reconciliation, then an operator). Compensations, retry policies, incidents. - Waiting is first-class. Events by instance, by correlation key (early ones are buffered) or by signed task token; timers and deadlines; polling of parties that cannot call back.
- Versions and operations. Old instances finish on their version; explicit migrations with a dry run. Journal with guard traces, "why is it here", move-to-state, retry, skip, resolve, suspend, cancel — all with actor and reason.
- No dependencies. Only PHP 8.2+. A Laravel bridge lives in dskripchenko/laravel-process-engine.
Install
composer require dskripchenko/process-engine
A process in a few lines
use Dskripchenko\ProcessEngine\Attributes\Idempotent; use Dskripchenko\ProcessEngine\Builder\Builder; use Dskripchenko\ProcessEngine\Process; final class DocumentApproval extends Process { public const VERSION = 1; public function define(Builder $p): void { $p->state('pending', fn (Builder $s) => $s ->entry(NotifyApprover::class) ->after('5 days', to: 'escalated') ->on('approved', to: 'done') ->on('rejected', to: 'declined', run: $this->keepReason(...))); $p->state('escalated', fn (Builder $s) => $s ->on('approved', to: 'done') ->on('rejected', to: 'declined', run: $this->keepReason(...))); $p->final('done'); $p->final('declined'); } private function keepReason(array &$context, array $event): void { $context['reason'] = $event['reason'] ?? null; } } #[Idempotent] final class NotifyApprover { public function __invoke(array $context): void { // send an e-mail; retried on failure } }
use Dskripchenko\ProcessEngine\Engine; $engine = Engine::inMemory(); // or a database store, see the docs $process = $engine->start(DocumentApproval::class, ['documentId' => 42]); $engine->send($process->id(), 'approved', key: 'msg-1'); $engine->drain(); // synchronous mode; workers in production $engine->get($process->id())->final(); // 'done'
Documentation
| English | Deutsch | Русский | 中文 | |
|---|---|---|---|---|
| Getting started | en | de | ru | zh |
| Concepts and guarantees | en | de | ru | zh |
| Defining processes | en | de | ru | zh |
| Structure: nesting, parallel, children | en | de | ru | zh |
| Effects and retry semantics | en | de | ru | zh |
| Events, timers, polling | en | de | ru | zh |
| Versions and migrations | en | de | ru | zh |
| Data pipelines: batches, switchable stages | en | de | ru | zh |
| Operating instances | en | de | ru | zh |
| Drawing with @dskripchenko/flow | en | de | ru | zh |
| Testing processes | en | de | ru | zh |
| Storage adapters | en | de | ru | zh |
Requirements
PHP 8.2 – 8.5. No runtime dependencies.
License
MIT. See LICENSE.