Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ When making changes in this repository:

- Keep changes focused and avoid unrelated refactors.
- Follow the existing PHP style: add `declare(strict_types=1);` to PHP files and keep code PSR-12 compatible.
- Preserve the existing architecture around `Workflow`, `Activity`, workflow stubs, signals, and generator-based workflow execution.
- Preserve the existing architecture around `Workflow`, `Activity`, workflow stubs, signals, and straight-line Fiber-based workflow execution.
- Add or update PHPUnit tests when behavior changes. Keep unit tests in `tests/Unit` and integration-style coverage in `tests/Feature`.
- Validate changes with the project quality cycle from the repository root:
1. `composer ecs`
2. `composer stan`
3. `composer unit`
4. `composer coverage`
5. `composer feature`
- Treat `composer coverage` as a hard requirement: unit-test coverage must remain at 100%.
- Treat `composer coverage` as a hard requirement: coverage must not fall below the versioned repository contract.
- Prefer solutions that stay compatible with the supported Laravel versions declared in `composer.json`.
1 change: 0 additions & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ jobs:
- name: Validate CI script syntax
run: |
bash -n \
scripts/ci/check-docs-release-audit.sh \
scripts/ci/laravel-embedded-upgrade-smoke.sh \
scripts/ci/check-packagist-release.sh \
scripts/ci/check-platform-conformance-mirror.sh \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
name: Release Docs Audit
name: Release Verification

on:
push:
tags:
- '2.0.0-alpha.*'
- '2.0.0-beta.*'
- '2.0.0-rc.*'
- '2.0.0'
- '2.*'
- '!2.*-*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag to audit, for example 2.0.0-alpha.201'
description: 'Stable 2.x release tag, for example 2.0.1'
required: true

permissions:
contents: read

jobs:
release-artifact:
name: Verify published Workflow artifact
published-package:
name: Verify published Workflow package
runs-on: ubuntu-latest
outputs:
laravel_published_matrix: ${{ steps.laravel-matrix.outputs.matrix }}
Expand All @@ -33,11 +31,11 @@ jobs:
php-version: '8.3'
tools: composer

- name: Derive exhaustive Laravel release qualification
- name: Derive supported Laravel upgrade matrix
id: laravel-matrix
run: echo "matrix=$(php scripts/ci/laravel-embedded-upgrade-matrix.php --scope=published)" >> "$GITHUB_OUTPUT"

- name: Resolve release tag
- name: Resolve stable release tag
id: release
shell: bash
env:
Expand All @@ -50,8 +48,8 @@ jobs:
tag="$GITHUB_REF_NAME"
fi
tag="${tag#v}"
if ! printf '%s\n' "$tag" | grep -Eq '^2\.0\.0((-(alpha|beta|rc)\.[0-9]+)?)$'; then
echo "::error::Invalid Workflow release tag for docs audit: $tag"
if ! printf '%s\n' "$tag" | grep -Eq '^2\.[0-9]+\.[0-9]+$'; then
echo "::error::Expected a stable Workflow 2.x tag, got: $tag"
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
Expand All @@ -62,47 +60,20 @@ jobs:
PACKAGIST_PACKAGE_VERSION: ${{ steps.release.outputs.tag }}
run: scripts/ci/check-packagist-release.sh

- name: Verify published platform conformance mirror
- name: Verify published platform contract
env:
WORKFLOW_PLATFORM_CONFORMANCE_VERSION: ${{ steps.release.outputs.tag }}
run: scripts/ci/check-platform-conformance-mirror.sh

docs-release-audit:
name: Verify public docs release-audit tuple
needs: release-artifact
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Require live docs release audit refresh
env:
DOCS_RELEASE_AUDIT_ARTIFACT: workflow
DOCS_RELEASE_AUDIT_VERSION: ${{ needs.release-artifact.outputs.release_tag }}
DOCS_RELEASE_AUDIT_EVIDENCE: docs-release-audit-evidence.json
DOCS_RELEASE_AUDIT_HANDOFF: docs-release-audit-handoff.json
run: scripts/ci/check-docs-release-audit.sh

- name: Upload docs release audit evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: docs-release-audit-evidence
path: |
docs-release-audit-evidence.json
docs-release-audit-handoff.json
if-no-files-found: warn

laravel-embedded-upgrade-published:
name: Published Laravel ${{ matrix.laravel }} / PHP ${{ matrix.php }} upgrade
needs: release-artifact
laravel-upgrade:
name: Laravel ${{ matrix.laravel }} / PHP ${{ matrix.php }} published upgrade
needs: published-package
runs-on: ubuntu-latest
timeout-minutes: 25

strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.release-artifact.outputs.laravel_published_matrix) }}
matrix: ${{ fromJSON(needs.published-package.outputs.laravel_published_matrix) }}

steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
Expand All @@ -114,8 +85,9 @@ jobs:
php-version: ${{ matrix.php }}
tools: composer

- name: Run the clean published-artifact upgrade journey
- name: Run the published-package upgrade journey
env:
LARAVEL_VERSION: ${{ matrix.laravel }}
WORKFLOW_V2_VERSION: ${{ needs.release-artifact.outputs.release_tag }}
WORKFLOW_V2_VERSION: ${{ needs.published-package.outputs.release_tag }}
run: scripts/ci/laravel-embedded-upgrade-smoke.sh

8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

## Unreleased

## 2.0.1 - 2026-09-01

- Workflow `2.0.1` keeps PHP exception traces Avro-portable when argument
capture is enabled, preserving each frame's durable fields while omitting
object and resource values that cannot cross the public payload boundary.

## 2.0.0 - 2026-09-01

- Workflow `2.0.0` promotes the fully qualified release-candidate runtime to
the stable 2.0 line without changing its durable execution behavior.

### 2.0 prerelease history

- Workflow `2.0.0-rc.55` treats the official stable-v1 Y and Base64 serializer
settings as nonblocking migration diagnostics while v1 runs drain, without
changing the Avro-only codec used for all new v2 payloads.
Expand Down
179 changes: 63 additions & 116 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,156 +1,103 @@
<p align="center"><a href="https://github.com/durable-workflow/workflow/actions/workflows/php.yml?query=branch%3Av2"><img src="https://github.com/durable-workflow/workflow/actions/workflows/php.yml/badge.svg?branch=v2" alt="GitHub Workflow Status"></a> <a href="https://codecov.io/gh/durable-workflow/workflow/branch/v2"><img alt="Codecov" src="https://codecov.io/gh/durable-workflow/workflow/branch/v2/graph/badge.svg"></a> <a href="https://packagist.org/packages/durable-workflow/workflow/stats"><img alt="Packagist Downloads (custom server)" src="https://img.shields.io/packagist/dt/durable-workflow/workflow"></a>
<a href="https://durable-workflow.com/docs/installation"><img src="https://img.shields.io/badge/docs-read%20now-brightgreen" alt="Docs"></a> <a href="https://github.com/durable-workflow/workflow/blob/v2/LICENSE"><img alt="Packagist License" src="https://img.shields.io/packagist/l/durable-workflow/workflow?color=bright-green"></a></p>
# Durable Workflow for Laravel

Durable Workflow (formerly Laravel Workflow) is a package for the Laravel web framework that provides tools for defining and managing workflows and activities. A workflow is a series of interconnected activities that are executed in a specific order to achieve a desired result. Activities are individual tasks or pieces of logic that are executed as part of a workflow.
<p align="center">
<a href="https://github.com/durable-workflow/workflow/actions/workflows/php.yml?query=branch%3Av2"><img src="https://github.com/durable-workflow/workflow/actions/workflows/php.yml/badge.svg?branch=v2" alt="Build status"></a>
<a href="https://codecov.io/gh/durable-workflow/workflow/branch/v2"><img src="https://codecov.io/gh/durable-workflow/workflow/branch/v2/graph/badge.svg" alt="Code coverage"></a>
<a href="https://packagist.org/packages/durable-workflow/workflow"><img src="https://img.shields.io/packagist/v/durable-workflow/workflow" alt="Latest Packagist version"></a>
<a href="https://packagist.org/packages/durable-workflow/workflow/stats"><img src="https://img.shields.io/packagist/dt/durable-workflow/workflow" alt="Packagist downloads"></a>
<a href="https://github.com/durable-workflow/workflow/blob/v2/LICENSE"><img src="https://img.shields.io/packagist/l/durable-workflow/workflow" alt="MIT license"></a>
</p>

Durable Workflow can be used to automate and manage complex processes, such as agentic workflows (AI-driven), financial transactions, data analysis, data pipelines, microservices, job tracking, user signup flows, sagas and other business processes. By using Durable Workflow, developers can break down large, complex processes into smaller, modular units that can be easily maintained and updated.
Durable Workflow is the embedded Laravel runtime for durable execution. Write
long-running workflows as ordinary PHP, keep completed work recorded through
worker restarts and application deploys, and use Laravel's queues, cache, and
database as the runtime.

Some key features and benefits of Durable Workflow include:
This package also provides the orchestration engine hosted by
[Durable Workflow Server](https://github.com/durable-workflow/server). Use the
[PHP SDK](https://github.com/durable-workflow/sdk-php) with Server or
[Durable Workflow Cloud](https://cloud.durable-workflow.com/) when workers need
to run outside the Laravel application or across PHP, Python, and Rust.

- Support for defining workflows and activities using simple, declarative PHP classes.
- Tools for starting, monitoring, and managing workflows, including support for queuing and parallel execution.
- Built-in support for handling errors and retries, ensuring that workflows are executed reliably and consistently.
- Integration with Laravel's queue and event systems, allowing workflows to be executed asynchronously on worker servers.
- Extensive documentation and a growing community of developers who use and contribute to Durable Workflow.
## Install

## Documentation

Documentation for Durable Workflow can be found on the [website](https://durable-workflow.com/docs/installation).

## Community

You can find us in the [GitHub discussions](https://github.com/durable-workflow/workflow/discussions) and also on our [Discord channel](https://discord.gg/xu5aDDpqVy).

## Sample App

There's also a [sample application](https://github.com/durable-workflow/sample-app) that you can run directly from GitHub in your browser.

## Usage
```bash
composer require durable-workflow/workflow:^2.0
php artisan migrate
```

Install the embedded Laravel runtime:
Run a Laravel queue worker or Horizon to execute workflows and activities:

```bash
curl -fsSL https://durable-workflow.com/install-sdk.sh | sh -s -- workflow
php artisan queue:work
```

This package owns Laravel service-provider integration, migrations, Eloquent
models, queue jobs, replay persistence, and in-process workflow and activity
authoring. It does not include a client or remote-worker runtime for the
standalone server.
## Your First Workflow

**1. Create a workflow**
```php
use function Workflow\V2\activity;
<?php

use Workflow\V2\Activity;
use Workflow\V2\Workflow;
use Workflow\V2\WorkflowStub;
use function Workflow\V2\activity;

class MyWorkflow extends Workflow
final class GreetActivity extends Activity
{
public function handle(string $name): string
{
$result = activity(MyActivity::class, $name);

return $result;
return "Hello, {$name}!";
}
}
```

**2. Create an activity**
```php
use Workflow\V2\Activity;

class MyActivity extends Activity
final class GreetWorkflow extends Workflow
{
public function handle(string $name): string
{
return "Hello, {$name}!";
return activity(GreetActivity::class, $name);
}
}
```

**3. Run the workflow**
```php
use Workflow\V2\WorkflowStub;

$workflow = WorkflowStub::make(MyWorkflow::class);
$workflow = WorkflowStub::make(GreetWorkflow::class);
$workflow->start('world');
```

```php
$workflow->output();
=> 'Hello, world!'
```

## Using a dedicated storage connection

By default all workflow persistence (every Eloquent model and every migration shipped
by this package) lives on your application's **default** database connection. To isolate
workflow state on its own database — for separate backup/retention/scaling, a different
driver, or tenant isolation — point the package at a dedicated connection:

```php
// config/workflows.php
'storage' => [
// null => the application's default connection (the default, unchanged behavior).
'connection' => Env::dw('DW_STORAGE_CONNECTION', 'WORKFLOW_STORAGE_CONNECTION', null),
],
```

```dotenv
# .env — must match a key under config('database.connections')
DW_STORAGE_CONNECTION=durable_workflow
echo $workflow->output(); // Hello, world!
```

When set, both the models and the migrations are routed to that connection, so
`php artisan migrate` creates the workflow tables there and all reads/writes target it.
Leaving it `null` preserves today's behavior exactly.

The schema/database is governed by the connection's own configuration — use
`search_path` for PostgreSQL or `database` for MySQL on that connection. There is no
separate schema option.

## Embedded and Polyglot Usage
Workflow code can coordinate activities, timers, signals, queries, updates,
child workflows, sagas, cancellation, retries, parallel work, side effects,
continue-as-new, search attributes, memo, and message streams. The runtime
persists execution history so replay can resume after process or host failure
without repeating completed activities.

This package provides the application-embedded version of Durable Workflow for Laravel.
## Choose a Deployment

Use it when your workflows and activities run within a Laravel application and you do not need workers written in other languages.

For standalone or polyglot orchestration, run the [standalone Durable Workflow server](https://github.com/durable-workflow/server) and install the [PHP SDK](https://github.com/durable-workflow/sdk-php) in framework-neutral PHP applications and remote workers:

```bash
curl -fsSL https://durable-workflow.com/install-sdk.sh | sh -s -- php
```

The standalone server allows PHP, Python, Rust, and other supported SDKs to participate in the same workflow system.

| Deployment mode | PHP package | Runtime owner |
| Deployment | Use it when | Runtime owner |
| --- | --- | --- |
| Embedded Laravel | `durable-workflow/workflow` | The Laravel application owns durable state and queue execution. |
| Standalone server host | `durable-workflow/workflow` inside `durable-workflow/server` | The server hosts Workflow's engine contracts and persistence. |
| Standalone PHP client or remote worker | `durable-workflow/sdk` | The SDK owns authentication, transport, protocol types, client operations, and worker polling. |
| Embedded Laravel | Workflows and activities live inside one Laravel application. | Your application owns persistence and queue execution. |
| Self-hosted Server | Workers run independently or in multiple languages. | Your team operates Server, MySQL, Redis, and optional Waterline. |
| Durable Workflow Cloud | You want a managed runtime for PHP, Python, and Rust workers. | Durable Workflow operates the runtime and persistence. |

## Sponsors

The Durable Workflow package is sustained by the community via sponsors and volunteers.

- <a href="https://github.com/discovery-ukraine" target="_blank" rel="noopener sponsored">Andriy Karpishyn</a>
- <a href="https://freispace.com" target="_blank" rel="noopener sponsored">Freispace Resource Scheduling</a>
- <a href="https://translateabook.com" target="_blank" rel="noopener sponsored">Translate a Book</a>
Embedded runs remain owned by the Laravel application. Moving new work to
Server or Cloud does not reinterpret existing embedded history.

## Monitoring
## Learn More

[Waterline](https://github.com/durable-workflow/waterline) is a separate UI that works nicely alongside Horizon. Think of Waterline as being to workflows what Horizon is to queues.
Waterline is a technical runtime UI for operators: use it for fleet
health, queues, waits, retries, failures, repair, and history
diagnostics. Business dashboards should read app-owned milestone
projections keyed by `workflow_id` and `run_id`, not Waterline data or
workflow runtime tables.
- [Embedded installation](https://durable-workflow.com/docs/2.0/installation/)
- [Embedded feature guides](https://durable-workflow.com/docs/2.0/category/embedded/)
- [Configuration reference](https://durable-workflow.com/docs/2.0/configuration/options/)
- [Deployment modes](https://durable-workflow.com/docs/2.0/polyglot/deployment-modes/)
- [Monitoring with Waterline](https://durable-workflow.com/docs/2.0/monitoring/)
- [Runnable Sample App](https://github.com/durable-workflow/sample-app)

### Dashboard View
Questions and design discussions are welcome in
[GitHub Discussions](https://github.com/durable-workflow/workflow/discussions)
and [Discord](https://discord.gg/xu5aDDpqVy).

![Waterline dashboard](https://raw.githubusercontent.com/durable-workflow/waterline/refs/heads/v2/docs/screenshots/dashboard.png)

### Workflow View
## Sponsors

![Waterline workflow detail](https://raw.githubusercontent.com/durable-workflow/waterline/refs/heads/v2/docs/screenshots/workflow-detail.png)
Durable Workflow is sustained by contributors and sponsors:

Refer to https://github.com/durable-workflow/waterline for installation and configuration instructions.
- [Andriy Karpishyn](https://github.com/discovery-ukraine)
- [Freispace Resource Scheduling](https://freispace.com)
- [Translate a Book](https://translateabook.com)
Loading