diff --git a/docker-compose.published.yml b/docker-compose.published.yml index 41f72c568..bb3c68f4c 100644 --- a/docker-compose.published.yml +++ b/docker-compose.published.yml @@ -16,7 +16,7 @@ name: durable-workflow-server # release whose default names another image). Set DW_SERVER_IMAGE to run # any other native image, by tag or digest; pin a digest for production # change control. -x-server-image: &server-image ${DW_SERVER_IMAGE:-durableworkflow/server:3.0.5} +x-server-image: &server-image ${DW_SERVER_IMAGE:-durableworkflow/server:3.1.0} services: server: diff --git a/docs/releases/3.1.0.md b/docs/releases/3.1.0.md new file mode 100644 index 000000000..1d2f084b0 --- /dev/null +++ b/docs/releases/3.1.0.md @@ -0,0 +1,117 @@ +# Durable Workflow Server 3.1.0 (native) + +Server 3.1.0 is a minor release of the native (Rust) Server. It is published +as `durableworkflow/server:3.1.0` and `ghcr.io/durable-workflow/server:3.1.0`, +and moves the `3.1`, `3` and `latest` tags. The published Compose file +defaults to it. + +**Upgrade:** the native schema is unchanged (version 8), so an upgrade from +3.0.x needs no schema-upgrade step. The worker protocol stays at `1.20` and +the control plane at version `2`. + +## Changes + +### Every worker answer carries the protocol envelope +Every worker-plane JSON object answer now carries `protocol_version` and +`server_capabilities` in its body, as PHP Server's `WorkerProtocol::json` +does. Before, native sent only the `X-Durable-Workflow-Protocol-Version` +header on most answers, so the published CLI's raw worker commands (for +example `dw workflow-task:poll`) refused them. +([server#1001](https://github.com/durable-workflow/server/issues/1001), +[#1003](https://github.com/durable-workflow/server/pull/1003), +[#1008](https://github.com/durable-workflow/server/pull/1008)) + +- A member the handler already set is kept. A missing or explicitly `null` + member is filled in, as PHP's `??=` does, and the other bytes of the body, + numbers included, are unchanged. +- **Heartbeat fix:** the activity heartbeat answer's `protocol_version` is now + the server's `1.20`, as PHP Server answers. Native used to echo the version + the worker sent. No published SDK reads that body field. +- A storage failure while resolving the namespace now answers with the + envelope and the version header, like any other worker answer. + +### Cluster info advertises client compatibility +`GET /api/cluster/info` now serves `client_compatibility` and +`supported_sdk_versions`, which the published CLI's `server:info` and +`doctor` read +([server#1005](https://github.com/durable-workflow/server/issues/1005), +[#1007](https://github.com/durable-workflow/server/pull/1007)). +Both come from one table, so they can't disagree: + +| Client | Supported range | +| --- | --- | +| sdk-php | `>=3.8.1,<4.0.0` | +| sdk-python | `>=2.13.0,<3.0.0` | +| sdk-rust | `>=4.10.3,<5.0.0` | +| cli | `>=2.0.0,<3.0.0` | + +**Recommended:** sdk-php 3.9.4 or later and sdk-python 2.14.0 or later. Those +releases handle an orphaned duplicate condition wait in replay (see +[Deferred to 3.1.1](#deferred-to-311)). The supported ranges above are +unchanged. + +`client_compatibility` (schema `durable-workflow.v2.client-compatibility`, +version 2, fail-closed) cites only the protocols native serves: +`auth_composition`, `control_plane` and `worker_protocol`. + +### Child start turn +A `start_child_workflow` command may set `await: "started"`. The completion +that starts the child also gives the parent a fresh workflow task, carrying +the child's committed identity, while the child runs. The default, +`await: "result"`, is unchanged. Native advertises it as +`child_workflow_start_turn: true` in cluster info `capabilities` and worker +`server_capabilities`. The contract is in +[`docs/contracts/child-start-turn.md`](../contracts/child-start-turn.md) +([server#966](https://github.com/durable-workflow/server/issues/966), +[#978](https://github.com/durable-workflow/server/pull/978)). + +### JSON doubles keep every digit +Native now parses JSON doubles exactly, so a value comes back with the digits +it was sent with, as PHP's `json_decode`/`json_encode` does. Before, a +16–17-digit double could come back one ULP off; for example, a memo's +`1.4820142857142857` was answered as `1.4820142857142855`. That affected +memos, search attributes, heartbeat details and other JSON values. The shared +`json-doubles` fixture checks this against published PHP on every supported +database +([server#1010](https://github.com/durable-workflow/server/issues/1010), +[#1011](https://github.com/durable-workflow/server/pull/1011)). + +## Known limitations +- **Typed double search attributes on PHP Server:** published PHP Server + 2.11.8 renders a typed double search attribute at PHP's 14-digit precision + in the run description and the visibility list (`1.4820142857142857` reads + back as `1.4820142857143`). 2.11.8 is the final PHP Server, so this won't be + fixed. Native 3.1.0 keeps every digit. +- **MySQL `json` columns round doubles:** on MySQL, history payloads (for + example WorkflowStarted's memo and search attributes, and heartbeat details) + hold MySQL's own parse of a double, which can be one ULP off. This happens + for PHP and native Servers alike. MariaDB, PostgreSQL and SQLite keep every + digit. The fix is planned for 3.2.0 + ([server#1016](https://github.com/durable-workflow/server/issues/1016)). +- **Provenance only:** images carry build-provenance attestations in both + registries but no SBOM yet + ([server#1012](https://github.com/durable-workflow/server/issues/1012), + planned for 3.2.0). +- **No sticky execution:** native doesn't implement sticky execution, so every + workflow task sends the full history + ([server#1017](https://github.com/durable-workflow/server/issues/1017), + planned for 3.2.0). + +## Deferred to 3.1.1 +- **Condition waits:** + - a re-sent `open_condition_wait` with the same `condition_wait_occurrence_id` + for a wait that is still open becomes idempotent; + - closing a run settles any open wait's timeout timer. + + Today a duplicate open records a second wait. While the run is still open, + the orphaned wait's timer can fire; after the run closes, its timer is left + pending but never fires. + ([server#1015](https://github.com/durable-workflow/server/issues/1015)) +- **SDK handling:** SDKs handle the orphaned wait in replay from sdk-php 3.9.3, + sdk-python 2.14.0 and sdk-rust 4.12.0 (pending, + [sdk-rust#192](https://github.com/durable-workflow/sdk-rust/issues/192)). + Older SDKs can fail replay with a NonDeterministic workflow error when the + orphan's timer fires + ([sdk-php#283](https://github.com/durable-workflow/sdk-php/issues/283), + [sdk-python#253](https://github.com/durable-workflow/sdk-python/issues/253), + [sdk-rust#192](https://github.com/durable-workflow/sdk-rust/issues/192)).