Skip to content

About

Runnable PHP, Python, and Rust examples for Durable Workflow 2.0, including Laravel embedded mode.

Topics

Resources

Contributing

Security policy

Stars

39 stars

Watchers

2 watching

Forks

Latest commit

 

History

942 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Durable Workflow Sample App

Quality Gate Application tests Embedded smoke Polyglot smoke Development image

Runnable examples for Durable Workflow 2.0. Start a PHP-authored workflow that calls Python and Rust activities through a standalone Server, build a workflow with any first-party SDK, or run the workflow engine inside Laravel.

Already have a Cloud namespace? Start with PHP on Cloud.

Open in GitHub Codespaces

Choose a path

Path Use it when Command
Service mode PHP, Python, and Rust workers share a standalone or managed runtime scripts/polyglot.sh
SDK playground You want to author a small workflow and activity in one SDK scripts/playground php, python, or rust
Embedded Laravel Laravel owns workflow execution and storage composer run dev

The Codespaces image already contains PHP, Composer, Python, Rust, Cargo, Docker Compose, Node, Chromium, dw, and rg. Setup installs only this repository's Composer and npm dependencies.

Service mode

Run the featured PolyglotWorkflow:

scripts/polyglot.sh

The command starts a published Durable Workflow Server and three workers. A PHP workflow sends an order calculation to a Python activity, then sends that result to a Rust activity that produces a receipt. The final result identifies all three runtimes and the artifact versions used for the run.

The build scripts prepare the pinned public central source and verify it before building. They use no credentials. For a manual Compose build, prepare it first:

scripts/prepare-apt-build-source.sh

The qualified tuple in polyglot/qualified-artifact-tuple.json pins every published artifact the journeys use: the native Server image by digest, Workflow, Waterline, the PHP/Python/Rust SDKs and the CLI. artifacts.workflow selects the embedded application's Composer package; the Composer lock must match it. Native Server is one process that creates its schema and default namespace and runs timers, schedules and activity timeouts itself, so the stacks start no bootstrap job, queue worker, scheduler or Server Redis. Override the Server with SAMPLE_APP_SERVER_VERSION or SAMPLE_APP_SERVER_IMAGE; only native 3.x images are accepted.

Before reusing an existing Server database, follow the Server 3.3 upgrade and rollback notes. The example tuple does not migrate an existing database for you.

On Native 3.3, stop every older PHP worker that can consume a task queue, including standby and autoscaling workers, before starting any SDK 3.11 worker on it. Once an anchored condition wait exists, keep that queue on SDK 3.11 or newer. See the PHP SDK upgrade guide.

Upgrade Python workers sharing a task queue together. Once v2 condition waits are recorded, keep every worker on SDK 2.14.1 or newer. Older versions cannot replay those waits. See the Python SDK compatibility notes for the remaining limits on legacy histories and predicate identity.

Rust SDK 4.11.2 preserves the original deadline of standalone condition waits after signals that leave the predicate false. Once a history records a reopened wait with a shorter timeout, keep that run on fixed workers. SDK 4.11.1 and earlier refuse that history. See the Rust SDK compatibility notes.

Workflow 2.20.3 can expose older pending stream messages that earlier workers left hidden. Receives on a stream kept in a workflow property now record at the current step. Earlier versions can replay these new histories differently after a rollback. See the Workflow compatibility notes, including the remaining query-handler limitation #1024.

Conversation on a PHP service-mode worker

App\Workflows\ServiceMode\Conversation\ConversationWorkflow is the embedded conversation written for the PHP SDK's Laravel bridge. It has the same turns, approval rule and continue-as-new, and the same durations, written as strings:

  • the conversation ends after '1 hour' without a message;
  • a proposal nobody decides within '5 minutes' changes nothing;
  • each activity has a '30 seconds' start-to-close timeout.

The SDK records each string as whole seconds, so '5 minutes' and 300 produce the same history. Point the application at a Server, then run a worker and the scripted conversation in two terminals:

export DURABLE_WORKFLOW_RUNTIME_URL=http://localhost:8080

DURABLE_WORKFLOW_PROCESS_ROLE=worker DURABLE_WORKFLOW_PROCESS_TOKEN='<worker credential>' \
  php artisan durable-workflow:worker

DURABLE_WORKFLOW_PROCESS_ROLE=client DURABLE_WORKFLOW_PROCESS_TOKEN='<client credential>' \
  php artisan app:service-mode-conversation --turns-per-run=2 \
    --message='Hello there' --message='Please refund my order' --message='Thanks'

Both processes use the application database for reply records, so run php artisan migrate first. Without --message the command is interactive.

Published child cancellation experiment

The full child experiment runs PHP, Python and Rust workers and cancellation clients against the published tuple. It covers nine child completion directions, five directions involving Rust for failure and recovery, and cooperative cancellation through legacy and operator access. (Native Server 3.x refuses the auth-disabled driver in release images, so the PHP-era anonymous batch is not run.) Waterline connects to that real Server and renders each original parent/child cancellation cascade. Browser checks compare the actual API response with the recorded identities, requester, deadline, delivery and cleanup outcomes on desktop and mobile.

With Docker Compose and Node 24 available:

npm ci
npx playwright install --with-deps chromium
while IFS='=' read -r name value; do export "$name=$value"; done < <(scripts/resolve-current-artifacts.sh)
SDK_CHILDREN_RESULT_DIR=./child-results scripts/sdk-children.sh

The command uses an isolated Compose project and removes its containers, data and task-built images on exit. The result directory retains original histories, request receipts, browser HTTP responses, DOM text and screenshots. Waterline binds an ephemeral loopback port and has its own disposable database.

The isolated sample-app-polyglot-demo Compose project remains available for inspection. Stop it with:

scripts/polyglot.sh down

See polyglot/README.md for the worker layout and the larger directional runtime matrix.

SDK playground

Use the same interface for each first-party SDK:

scripts/playground php
scripts/playground python
scripts/playground rust

Each command creates editable source under .playground/<language>, starts an isolated local Server and Waterline, waits for the worker registration, starts the workflow, verifies its result and history, and prints the matching Waterline run URL. Existing authored files are preserved.

The Rust command first builds your worker and client with the committed lock and at most two Cargo jobs. Preparation has a five-minute limit and reports build errors separately; the worker then has its own 60-second registration window. This also applies when you use a managed runtime.

The generated workflow and activity are yours to edit. .playground/ and the default evidence files are ignored by Git; the evidence is a run report, not application source. To keep authored code in your project, choose a directory with --source, review the generated files, and commit only your source, not credentials or run reports. Existing files are preserved on subsequent runs.

Create a caller-owned project elsewhere with --source:

scripts/playground rust --source "$HOME/my-durable-rust-worker"

Inspect the effective contract without starting anything:

scripts/playground doctor
scripts/playground rust --print-contract

doctor checks the toolchains and Docker access. --print-contract prints the JSON contract that the same journey would use and exits. It shows the workflow type, activity type, task queue, input, expected result, worker command, and start command. It probes no tools, reads no credentials, starts no services, and writes no files. It accepts the same --source, --runtime, --runtime-url, --namespace, and --task-queue selections as a run, and it rejects --evidence because inspection writes no run report. A local run replaces {run_suffix} in the printed task queue with a fresh value.

Remove one playground's containers and state with:

scripts/playground down rust

Managed runtime

PHP on Cloud

The same authored project can run against Durable Workflow Cloud or another existing runtime, without starting a local Server or Waterline. Use the exact runtime URL and namespace shown by Cloud; do not append /api. Supply the runtime worker and client SDK credentials, not a Cloud control-plane API key:

export DURABLE_WORKFLOW_WORKER_TOKEN='<worker credential>'
export DURABLE_WORKFLOW_CLIENT_TOKEN='<client credential>'

scripts/playground php \
  --runtime managed \
  --runtime-url 'https://runtime.example/namespaces/example' \
  --namespace 'example' \
  --task-queue 'my-php-worker'

The worker receives only the worker credential, and the client receives only the client credential. The runner prints the workflow type, activity type, task queue, worker command, start command, and expected result before it runs. Expect Worker ready: target=managed, followed by Completed php workflow and the result containing workflow_runtime: php and activity_runtime: php. Use python or rust in place of php for the other SDKs.

This PHP path is service mode using the Laravel bridge, not the embedded workflow engine. Laravel provides configuration, dependency injection, PSR logging, and the SDK test fake. The SDK worker polls Cloud; Laravel's embedded queue worker is not its executor. The generated bootstrap.php and activity use Laravel, while the core PHP SDK also supports framework-free processes. For those, use scripts/playground scaffold php --standalone --source <dir> to inspect the installed SDK's own worker/client examples.

Embedded Laravel

Start Laravel's web server, queue worker, logs, and Vite process:

composer run dev

In a second terminal, start the example workflow:

php artisan app:workflow

Open /waterline on the forwarded application URL to inspect the run. Run the Laravel workflow and activity tests with:

php artisan test

The embedded examples live under app/Workflows, with focused tests under tests/Feature/Workflows.

Example index

Example What it demonstrates
SimpleWorkflow Minimal embedded workflow and activity
AccountOnboardingWorkflow Signals, timers, and external interaction
BatchProcessingWorkflow Bounded concurrency and fan-out
DataPipelineWorkflow Multi-step activity orchestration
DeployWorkflow Child workflows and deployment stages
SagaWorkflow Compensation after a failed step
SubscriptionWorkflow Long-running lifecycle and cancellation
SandboxAgentWorkflow Durable sandbox provisioning, snapshots, recovery, and cleanup
PolyglotWorkflow PHP workflow with Python and Rust activities
ConversationWorkflow (php artisan app:conversation) Long-lived conversation: ordered signal input, fake model activity, human approval, status query, continue-as-new, and recovery after a lost worker
Service-mode ConversationWorkflow (php artisan app:service-mode-conversation) The same conversation on a PHP SDK worker, with '1 hour' and '5 minutes' written as friendly durations

Repository map

Path Purpose
app/Workflows/ Embedded Laravel examples
polyglot/ Service-mode workers and Compose topology
playground/ PHP, Python, and Rust authoring templates
scripts/polyglot.sh Featured PHP to Python to Rust run
scripts/playground Symmetric SDK authoring runner
.devcontainer/ Prepared Codespaces development image

Local development

Codespaces is the shortest path. For an existing PHP 8.4, Node, Docker, and Docker Compose environment:

cp .env.example .env
composer install
npm install
php artisan key:generate
scripts/prepare-apt-build-source.sh
docker compose up -d
php artisan migrate
composer run dev

Run the focused checks with:

php artisan test
npm test
npm run build

Documentation

The Laravel 12 / Durable Workflow 1.x sample remains available on the Laravel-12 branch.

License

Durable Workflow Sample App is open source software licensed under the MIT license.

About

Runnable PHP, Python, and Rust examples for Durable Workflow 2.0, including Laravel embedded mode.

Topics

Resources

Contributing

Security policy

Stars

39 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages