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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.11.0] - Unreleased

### Fixed

- Bound failure messages, stacks and diagnostic payloads before reporting them.
The complete encoded request defaults to 1 MiB, including JSON escaping and
markers, and respects lower configured or discovered limits. Preserve failure
type, retry policy and claim identity; refuse an identity that cannot fit.

## [2.10.1] - Unreleased

### Fixed
Expand Down
42 changes: 42 additions & 0 deletions docs/reference/worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,48 @@ isolated worker processes and their resource limits. The separately
negotiated cooperative-cancellation capability retains its supervised process
execution; selecting a default thread does not enable that protocol.

## Bounded failure reports

This behavior is available in unreleased SDK source. Published packages still
need the compatible release before these limits apply.

Failure reports retain at most 62 KiB of UTF-8 message text, 128 KiB of stack
text and 64 KiB of serialized details and diagnostics. These budgets include
truncation markers. The complete encoded JSON request body defaults to at most
1 MiB, counting JSON escaping, claim identities, command batches and metadata.
The message budget reserves 2 KiB below the original 64 KiB ceiling for
runtime-derived summaries.
A lower discovered Server `limits.max_payload_bytes` also applies. Configure
`Client(..., failure_report_limit_bytes=...)` when a proxy or transport has a
lower request limit. This option can lower the default cap; it cannot raise it.
Query-client clones inherit it. Payload warning thresholds remain advisory.

Oversized diagnostics produce a visible `[truncated ...]` message marker with
structured omitted-field names and original byte sizes. Activity failures also
carry this information in `failure.diagnostics.failure_report`; terminal
workflow failures use `exception.diagnostics.failure_report`. Other existing
report shapes keep the diagnostic JSON in the message marker. Unknown sizes
are `null` when optional details could not be encoded. Avro details are kept as
an intact valid envelope or omitted whole, before an unnecessary payload upload.

The original failure type, retry/non-retryable choice, authored retry delay and
claim identity remain exact. Activity, workflow-task, query and update rejection
reports, terminal workflow/update failures and local-activity attempt reports
share the complete-request bound. A workflow-task replay failure still leaves
the run open for repair; it does not become a terminal workflow failure.

A local activity's failure is bounded before workflow code observes it. First
execution and cold replay therefore see the same persisted message. If a later
command batch or newly discovered lower limit cannot fit that observed value,
reporting fails explicitly rather than changing a value already used by the
workflow. Prepared local activities observe the runtime's canonical history.

If essential identity or semantic fields cannot fit even without optional
text, the client raises `FailureReportTooLarge` before sending the report.
This reporting refusal is separate from the application failure. The worker's
existing reporting-error log identifies it; shortening a task ID or replacing
the application type would change which failure the runtime records.

## Poll failures and recovery

This backoff requires Python SDK 2.10.0 or later. Earlier packages use a fixed
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "durable-workflow"
version = "2.10.1"
version = "2.11.0"
description = "Python client and worker SDK for Durable Workflow Cloud and self-hosted Server"
readme = "README.md"
requires-python = ">=3.10"
Expand Down Expand Up @@ -76,8 +76,8 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main"
durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main"

[tool.durable-workflow]
product-train = "2.10.1"
registry-version = "2.10.1"
product-train = "2.11.0"
registry-version = "2.11.0"
supported-server-versions = "2.8.0"
worker-protocol-version = "1.20"
control-plane-version = "2"
Expand Down
2 changes: 2 additions & 0 deletions src/durable_workflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
ExternalPayloadUnauthorized,
ExternalPayloadUnavailable,
ExternalPayloadUnsupported,
FailureReportTooLarge,
InvalidArgument,
InvalidWorkflowDefinition,
NamespaceNotFound,
Expand Down Expand Up @@ -334,6 +335,7 @@
"testing",
"workflow",
"DurableWorkflowError",
"FailureReportTooLarge",
"EXTERNAL_PAYLOAD_REFERENCE_SCHEMA",
"RUNTIME_EXTERNAL_PAYLOAD_REFERENCE_SCHEMA",
"AzureBlobExternalStorage",
Expand Down
Loading
Loading