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
14 changes: 14 additions & 0 deletions docs/portal/build/workflows-activities.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ $worker->registerWorkflow(

The sequence, type, and details of context operations are durable. Changing them while old histories are still running can raise `NonDeterministicWorkflow`. Deploy replay-compatible code or drain incompatible histories before removing an old branch.

## Keep invocation state local

Create execution-local variables and temporary mutable objects inside the
workflow method. Workflow replay reconstructs durable values through `WorkflowContext`.
Apply the same rule to queries and updates.

The released SDK shallow-clones attributed workflow handlers without rerunning
their constructors. Constructor-created nested objects and referenced
properties can remain shared across workflows and replay attempts. Do not use
them, injected services, static properties or captured shared objects for
execution-local mutable state. This handler-lifetime limitation remains open in
[#16](https://github.com/durable-workflow/sdk-php/issues/16); the proposed
fresh-construction correction is not released.

## Call a registered service

This authoring API is introduced in the PHP SDK 2.3 prerelease. Install it with
Expand Down
17 changes: 11 additions & 6 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,18 @@ interleaved workflow executions cannot consume one another's execution state.
Generator-returning workflow handlers are not part of the 2.0 service-mode
contract.

Attribute-discovered workflow entry points, queries, and updates receive a fresh
Attribute-discovered workflow entry points, queries, and updates receive a
shallow clone of the registered workflow handler template for every invocation.
The template retains constructor-injected collaborators, but mutable properties
on the workflow handler always begin at their registration-time values. Activity
handlers are different: the worker invokes the resolved activity service
instance directly across tasks. Low-level callable registrations likewise keep
the lifetime and captured state of the callable supplied by the application.
The SDK does not rerun the constructor. Nested objects and referenced properties can remain
shared under [PHP's cloning rules](https://www.php.net/manual/en/language.oop5.cloning.php),
including constructor-created state and injected collaborators. This does not
provide complete workflow-state isolation. Keep execution-local state in method
variables and construct temporary objects inside each invocation. The remaining
handler-lifetime defect is tracked in [#16](https://github.com/durable-workflow/sdk-php/issues/16).

Activity handlers use the resolved activity service instance directly across
tasks. Low-level callable registrations keep the lifetime and captured state
of the callable supplied by the application.

The runtime fetches all paginated history before replay. Activity handlers can
heartbeat and observe cancellation. Query handlers receive immutable committed
Expand Down
25 changes: 14 additions & 11 deletions docs/sdk-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,22 +440,25 @@ required constructor arguments are instantiated automatically. Pass any PSR-11
`ContainerInterface` as the third argument to `Worker::create()` when handlers
have application dependencies.

Attributed workflow classes have a replay-scoped lifecycle. Registration
captures a clean handler template, then each workflow task replay, query, and
update runs on a fresh shallow clone. Mutable properties on the workflow object
therefore cannot cross workflow IDs, runs, or replay attempts, while
constructor-injected collaborators retain their configured identity. Keep
workflow-local mutable state directly on the handler; injected collaborators
are shared services and must not be used to hold execution-local state.
Workflow handler classes must remain cloneable.
Registration retains a workflow handler template. Each attributed workflow task
replay, query, and update runs on a shallow clone of it. The constructor is not
rerun, and shallow cloning does not automatically isolate nested objects or referenced properties.
Mutating constructor-created object state can therefore affect another workflow
ID, run or replay. This limitation remains open in
[#16](https://github.com/durable-workflow/sdk-php/issues/16).

Keep workflow-local state in method variables. Create temporary mutable objects
inside each workflow, query or update invocation. During workflow replay,
reconstruct durable values through `WorkflowContext`. Injected collaborators retain their configured
identity and must not hold execution-local state. Workflow handler classes must
remain cloneable. The proposed fresh-construction API in #111 is not released.

Activity services have worker-scoped lifetimes instead: their resolved instance
is reused for activity tasks, so they can retain clients and other service
resources. The explicit `registerWorkflow()`, `registerQuery()`, and
`registerUpdate()` low-level methods also invoke the supplied callable as-is;
state captured by such a callable remains owned by the application. Use
attribute-based workflow registration when the SDK should provide replay-state
isolation.
state captured by such a callable remains owned by the application. Neither
registration style makes shared mutable objects safe workflow-local storage.

Pass a PSR-3 `LoggerInterface` with the named `logger` argument; lifecycle,
retry, shutdown, and handler failures then use the application's normal logging
Expand Down
Loading