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
2 changes: 1 addition & 1 deletion docker-compose.published.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
117 changes: 117 additions & 0 deletions docs/releases/3.1.0.md
Original file line number Diff line number Diff line change
@@ -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)).
Loading