Aller au contenu principal
Version: 2.0

Portable Worker Affinity

Service workers implement the features listed below through Server's worker protocol. SDK versions and worker configuration determine what is available.

Local activities, worker sessions, and sticky execution share one portability rule: a service worker must declare each feature as supported or explicitly refused. Protocol version 1.18 is the floor for these declarations. The server rejects a flat routing capability unless the worker's structured manifest marks the same feature as supported.

SDK support​

SDK workerLocal activitiesWorker sessionsSticky execution
PHPSupportedSupportedSupported
PythonSupported since 2.2.0Supported since 2.3.0Supported since 2.5.0 with sticky_cache_capacity above zero
RustSupported since 3.1.0 with Worker::local_activities(true)Supported since 3.2.0 with Worker::worker_sessions(true)Supported since 3.4.0 with Worker::sticky_cache(...)

Workers advertise only the capabilities implemented and enabled for their profile. Rust local activities, sessions and sticky execution, and Python sticky execution, require explicit opt-in. Older SDK versions refuse capabilities they do not implement. Ordinary workflows and queued activities use complete durable-history replay without these optimizations.

Local activity recording​

PHP, Python and opted-in Rust workers run a local activity inside the workflow worker. The workflow-task completion contains the arguments, attempt outcomes, retry and timeout settings, heartbeat progress, and terminal result or failure. The server records that sequence atomically as normal activity history marked execution_mode=local.

Replay consumes the recorded terminal activity event. It does not invoke the local handler again. A worker lost before Server commits completion can execute the handler again, so external effects must be idempotent.

Ordinary PHP workers execute the synchronous handler inline. Cancellation and elapsed heartbeat, per-attempt, and total timeouts are observed before an attempt, at ActivityContext::heartbeat(), or after the handler returns. These handlers must remain short and divide blocking work with safe heartbeat boundaries.

Python and Rust async callbacks must yield to their language runtime. Rust renews the exact workflow-task lease independently of application heartbeats, drops the callback on timeout, lost authority or worker shutdown, and records bounded attempt and heartbeat reports. See the Rust local activity example and API reference.

PHP workers that enable cooperative cancellation use protocol 1.20 and supervised callback processes for prepared local activities. Rust inline local execution uses a separate ordinary worker profile and cannot be combined with prepared cooperative local supervision. Blocking callbacks need process supervision to guarantee physical stop.

Worker session lifecycle​

The PHP, Python and Rust SDKs expose typed session options and create, use, renew, and close operations. Options include requirements, queue, lease duration, total TTL, maximum concurrent activities, and reacquisition policy. A worker closes the sessions it holds during graceful shutdown.

If a holder disappears, its lease and concurrency reservation expire. A new holder may reacquire the session when requirements match, but it must rebuild worker-local resources before the first activity uses them. Session identity never makes process memory durable.

Reacquisition preserves the session's original absolute TTL. Renewal extends holder authority without extending that TTL. Use Server 2.5.1 or newer for original TTL preservation and recorded session routing during cold replay. See the Rust session example and WorkerSessionOptions.

Sticky execution and cold replay​

The PHP, Python and Rust caches are bounded and keyed by the exact workflow ID, run ID, and worker build ID. They report hit, miss, eviction, and forced_cold_replay. Expiry, eviction, worker replacement, holder loss, or a build mismatch discards the optimization and replays complete durable history.

Use Python SDK 2.5.0 with Server 2.5.10 or newer. Its cache is disabled by default. Enable it with sticky_cache_capacity and set the retained history byte limit and TTL for your worker. It stores encoded durable history and can reuse validated page cursors to save repeated downloads. Allow additional memory for decoding and deterministic replay. See the Python sticky execution guide and runnable example.

Rust SDK 3.4.0 supports the same published Server baseline. Enable its cache with Worker::sticky_cache(StickyCacheOptions::new(...)) and configure the encoded-history byte limit and TTL. Each replay decodes a fresh snapshot. Reused history cursors are checked against the current task lease and durable history before a warm hit is accepted. The cache holds history, not live workflow instances or session resources. See StickyCacheOptions and the runnable Rust example.

Server 2.5.10 preserves full replay for PHP SDKs before 2.2.0. Use PHP SDK 2.2.0 or newer to consume replay hints for histories beginning with StartAccepted.

Sticky routing is an affinity optimization. A forced cold replay is diagnostic evidence that the optimization was unavailable; it is not a workflow correctness failure. Workflow code must remain deterministic with an empty cache.

Safe defaults and rolling fleets​

Ordinary workflows require no session or sticky configuration. Mixed-version fleets fail closed at the protocol floor: the server checks the negotiated version, the flat capability, the structured manifest, and exact sticky cache identity before accepting feature-specific completion data.

The published cross-SDK scenario manifest covers manifest truth, local-activity replay, session holder loss and reacquisition, sticky hits and eviction, worker replacement, forced cold replay, and zero-configuration workflows.

For embedded Laravel implementations, see Local Activities, Worker Sessions, and Sticky Execution. Those APIs belong to the workflow package. Use the corresponding SDK's API for service workers.