Skip to content

Commit cb79967

Browse files
docs: describe language-neutral payload codec envelope
Documents the payload codec contract introduced for zorporation/durable-workflow#164: canonical codec names, how `POST /api/workflows` accepts plain JSON arrays vs. explicit `{codec, blob}` envelopes, per-run codec propagation, and the trade-offs between the `json` codec (portable) and the legacy PHP codecs (PHP-only but preserves arbitrary PHP values). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 58879bd commit cb79967

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

docs/configuration/worker-protocol.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,67 @@ The `ActivityTaskBridge` contract defines how an external worker interacts with
145145

146146
Activity heartbeat responses include `can_continue` and `cancel_requested` fields, allowing long-running activities to respond to cancellation requests.
147147

148+
## Payload Codecs
149+
150+
Every payload byte string that crosses the worker-protocol boundary is tagged with a **`payload_codec`** naming the format of the accompanying blob. Codecs are language-neutral so any SDK — PHP, Python, Go, TypeScript, Rust — can encode and decode payloads without sharing a runtime or an HMAC key.
151+
152+
### Canonical Codec Names
153+
154+
| Codec | Description |
155+
|-------|-------------|
156+
| `json` | Raw UTF-8 JSON document (default for new workflows). No wrapping, no signing. Round-trips any JSON-representable value. |
157+
| `workflow-serializer-y` | PHP `SerializableClosure` with byte-escape encoding. Legacy; requires a shared `config('app.key')` between server and worker. |
158+
| `workflow-serializer-base64` | PHP `SerializableClosure` with base64 encoding. Legacy. |
159+
160+
Legacy fully-qualified PHP class names (e.g. `Workflow\Serializers\Y`) are accepted as aliases so runs persisted before the codec rename keep decoding.
161+
162+
### Wire Format: Payload Envelope
163+
164+
On fields that carry payload bytes (`arguments`, `result`, `payload`, etc.), the worker protocol surfaces the codec alongside the opaque string. Poll responses look like:
165+
166+
```json
167+
{
168+
"task_id": "...",
169+
"payload_codec": "json",
170+
"arguments": "[\"hello\", 42]",
171+
"history_events": [ ... ]
172+
}
173+
```
174+
175+
The worker reads `payload_codec` to choose a decoder. A non-matching codec is a clear error — the worker should not attempt to sniff or guess.
176+
177+
### Starting a Workflow
178+
179+
`POST /api/workflows` accepts `input` in two shapes:
180+
181+
1. **Plain JSON array** — the server JSON-encodes and tags the run with `payload_codec = "json"`.
182+
183+
```json
184+
{ "workflow_type": "MyWorkflow", "input": ["hello", 42] }
185+
```
186+
187+
2. **Explicit envelope** — for clients that already hold pre-encoded bytes (e.g. a PHP client with a SerializableClosure payload):
188+
189+
```json
190+
{
191+
"workflow_type": "MyWorkflow",
192+
"input": { "codec": "json", "blob": "[\"hello\", 42]" }
193+
}
194+
```
195+
196+
The server stores the blob verbatim and tags the run with the declared codec.
197+
198+
The chosen codec is stored on the `WorkflowRun` and **propagates for the life of the run**: activity arguments, results, signal/update arguments, and child-workflow inputs all use the same codec unless explicitly overridden.
199+
200+
### Per-Codec Compatibility
201+
202+
- **`json`** — portable across all SDKs. JSON-native types only (no Eloquent models, closures, or arbitrary PHP objects).
203+
- **`workflow-serializer-y` / `workflow-serializer-base64`** — PHP-only. Supports arbitrary PHP values (including Eloquent models, closures) but cannot be read by non-PHP workers. Use only when server and workers all run the same PHP codebase with a shared app key.
204+
205+
### Default Codec
206+
207+
The default codec is chosen from `config('workflows.serializer')` for installations that explicitly set it; new deployments default to `json`. Clients that omit `input` on `POST /api/workflows` inherit the default.
208+
148209
## Resolving the Bridges
149210

150211
Both bridges are registered in the Laravel container and can be resolved directly:

0 commit comments

Comments
 (0)