The first-party PHP client and worker SDK for Durable Workflow Cloud and self-hosted Durable Workflow Server. Use it from plain PHP, Laravel, or Symfony to run durable workflows outside the application process while keeping framework-native configuration, dependency injection, commands, logging, and tests.
composer require durable-workflow/sdkThe SDK requires PHP 8.1 or newer. It uses the official apache/avro package
for portable payloads and accepts any PSR-18 HTTP client.
Upgrading from PHP SDK 2 requires a workflow registration migration. Register
workflow classes or a WorkflowFactory that constructs a fresh handler instead
of passing prebuilt workflow objects. Workflow container bindings must be
transient, while injected collaborators may remain shared. Constructors run
during replay and must be free of external side effects. See the
registration migration guide.
| Starting point | Recommended guide |
|---|---|
| Plain PHP client or worker | First workflow |
| Laravel v1 or v2 embedded | Choose a Laravel ownership model |
| Laravel service mode | Laravel service-mode bridge |
| Laravel HTTP hosting | FPM and optional Octane example |
| Symfony service mode | Symfony bundle |
| Runtime authentication | Authentication guide |
Laravel applications can keep Durable Workflow embedded or move execution to Cloud or Server. The service-mode bridge supplies container bindings, config, an Artisan worker command, diagnostics, a facade, and a test fake. Symfony gets the same application-shaped experience through its bundle and Console worker.
Handlers can be ordinary attributed classes resolved by the worker container:
<?php
use DurableWorkflow\Attribute\Activity;
use DurableWorkflow\Attribute\Workflow;
use DurableWorkflow\Worker\ActivityContext;
use DurableWorkflow\Worker\WorkflowContext;
final class GreetingWorkflow
{
#[Workflow('example.greeting')]
public function run(WorkflowContext $context, string $name): array
{
$greeting = $context->activity('example.greet', [$name]);
return ['greeting' => $greeting];
}
}
final class GreetingActivities
{
#[Activity('example.greet')]
public function greet(ActivityContext $context, string $name): string
{
return "Hello, {$name}";
}
}Register the classes on a task queue and start polling:
use DurableWorkflow\Client;
use DurableWorkflow\Worker;
$client = new Client(
getenv('DURABLE_WORKFLOW_RUNTIME_URL'),
namespace: getenv('DURABLE_WORKFLOW_NAMESPACE'),
workerToken: getenv('DURABLE_WORKFLOW_WORKER_TOKEN'),
);
Worker::create($client, 'greetings')
->register(GreetingWorkflow::class, GreetingActivities::class)
->run();Start the workflow from a client process using a client-role credential:
$client = new Client(
getenv('DURABLE_WORKFLOW_RUNTIME_URL'),
namespace: getenv('DURABLE_WORKFLOW_NAMESPACE'),
controlToken: getenv('DURABLE_WORKFLOW_CLIENT_TOKEN'),
);
$handle = $client->startWorkflow(
workflowType: 'example.greeting',
workflowId: 'greeting-'.bin2hex(random_bytes(12)),
taskQueue: 'greetings',
input: ['PHP'],
);
var_dump($handle->result());For Cloud, use the complete namespace runtime URL exactly as provisioned. For
self-hosted Server, use its origin such as http://localhost:8080. Keep client
and worker credentials in separate processes.
The complete plain PHP quickstart includes the three runnable files, environment setup, expected output, and common failure diagnostics.
- Workflows, activities, child workflows, timers, retries, and heartbeats
- Signals, queries, updates, condition waits, and message streams
- Parallel work, sagas, cancellation, continue-as-new, and version markers
- Schedules, search attributes, memo, external payloads, and worker versioning
- Replay testing, in-memory client fakes, Laravel and Symfony test helpers
- Stable workflow handles and machine-readable runtime diagnostics
Configure optional execution tracing and log correlation with your application-owned OpenTelemetry provider. Durable caller propagation requires the connected Server to advertise the supported capability.
See the complete SDK reference for control-plane APIs, worker configuration, Message Streams, framework setup, and testing examples. The generated API reference documents every public class and method.
When the runtime advertises activity_lease_renewal, the managed Worker keeps
an activity's runtime lease and Worker presence alive independently of a blocking
callback. Ordinary callbacks keep running inline with their original injected
services and captured memory. This requires PHP CLI with proc_open enabled.
Runtime maintenance does not record application progress or extend an activity,
heartbeat, workflow or worker-session TTL deadline. Continue calling
ActivityContext::heartbeat() when an activity has a heartbeat timeout.
After authority is lost, the Worker discards late outcomes. It cannot undo
external side effects or forcibly stop ordinary inline application code.
The default HTTP transport and static worker credentials work automatically.
Custom HTTP clients or dynamic authentication require
withActivityLeaseBootstrap()
so the independent process recreates their actual TLS and authentication settings.
Cooperative requests let workflow code perform bounded, replayable cleanup.
Use a Server that advertises protocol 1.20 and the required capabilities, set
the Client's workerProtocolVersion to '1.20', and construct the Worker with
enableCooperativeCancellation: true. Enable enablePreparedLocalActivities
for durable local callback admission, stop receipts and explicit local policies.
Independently cancellable scopes remain disabled.
This opt-in requires Unix CLI with pcntl and posix. Activity callbacks run
in supervised child processes so cancellation can stop blocking code without
application heartbeats. Open handler-owned connections in the callback process
and return results explicitly. Changes to captured process memory do not update
the owning worker.
Use requestCancellation() for cooperative cleanup. Existing cancel() closes
the run immediately. See the cancellation guide
for operation policies, immutable context, shielding and recovery.
composer install
composer test
composer analyse
composer benchmark-avro-valueSee CONTRIBUTING.md for contribution and validation details.
MIT