diff --git a/docker-compose.published.yml b/docker-compose.published.yml index 4352e1217..1f7009fe7 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.5.0} +x-server-image: &server-image ${DW_SERVER_IMAGE:-durableworkflow/server:3.6.0} services: server: diff --git a/docs/releases/3.6.0.md b/docs/releases/3.6.0.md new file mode 100644 index 000000000..490278243 --- /dev/null +++ b/docs/releases/3.6.0.md @@ -0,0 +1,87 @@ +# Durable Workflow Server 3.6.0 (native) + +Server 3.6.0 lets clients read an update's outcome later, gives workflow tasks +a replay-safe entry clock, resumes retried activities from their last +heartbeat, and scans every published image for fixable vulnerabilities. Its +exact images are `durableworkflow/server:3.6.0` and +`ghcr.io/durable-workflow/server:3.6.0`; the published Compose default selects +3.6.0. Rolling aliases move separately after published-image qualification. + +## Upgrade + +**No schema upgrade.** The native schema stays at 12 on MySQL, MariaDB and +PostgreSQL and at 11 on SQLite, so a 3.5.0 database runs on 3.6.0 as it is. +Replace the image and restart. Databases still on 3.4.x or earlier need the +[3.5.0 schema upgrade](3.5.0.md#upgrade) first. + +Rolling back to 3.5.0 is an image change. The worker protocol stays at `1.20` +and the control plane at version `2`. + +## Read an update's outcome later + +`GET /api/workflows/{workflow_id}/updates/{update_id}` returns an accepted +update's receipt without admitting another update +([#1131](https://github.com/durable-workflow/server/issues/1131)). It answers +like submission: 202 with `update_status: accepted` while the handler runs +(never a null result), 200 when it completed (an encoded null result +included), 422 when it failed. With `wait_for=completed` and +`wait_timeout_seconds` it waits for the outcome. A missing or pruned update is +404 `update_not_found`, which does not prove the update was never admitted. +Cluster info advertises `update_outcome_reads: true`. See +[Update outcome reads](../contracts/update-outcome-reads.md). + +## Replay-safe entry clock on workflow tasks + +Each workflow task carries `replay_clock`, the instant the run's replay starts +from, so an SDK's replay-safe clock has a value at ordinary workflow entry +([#1132](https://github.com/durable-workflow/server/issues/1132)). Ordinary, +continued and child runs use their own start. A redriven run uses its source's +replay anchor, only when the redrive command and link agree; otherwise the +object is omitted. See +[Worker replay entry clock](../contracts/worker-replay-entry-clock.md). + +## Activity retries resume from the last heartbeat + +A worker that lists `activity_heartbeat_resume` receives +`last_heartbeat_details` and `last_heartbeat_at` on a retry attempt's claim: +the latest acknowledged heartbeat from earlier attempts of the same activity +([#1139](https://github.com/durable-workflow/server/issues/1139)). Native +advertises `activity_heartbeat_resume: {supported: true, version: 1}` in +worker `server_capabilities`. + +## Vulnerability scan of published images + +Each release now scans both published architecture images with a pinned +Trivy and keeps a compact receipt. A HIGH or CRITICAL finding with a fixed +version fails the release run, which holds alias promotion. `latest` is +rescanned weekly ([#802](https://github.com/durable-workflow/server/issues/802)). + +The first scan found CVE-2026-109518 (HIGH) in `apt` and `libapt-pkg6.0` +2.6.1 in the 3.5.0 runtime base. 3.6.0 moves the base to the current Debian +12 bookworm-slim image, which has 2.6.2. The server never runs apt. Security +recorded the remaining unfixed Debian rows as accepted residual risk on #802. + +## Other changes + +- A workflow-task completion that carries commands may be up to 16 times the + per-payload limit (32 MiB by default), so large fan-outs complete. A larger + one is refused with 413 `payload_too_large` and + `limit_kind: workflow_task_completion_bytes`. Each command's arguments still + meet the per-payload limit + ([#1136](https://github.com/durable-workflow/server/issues/1136)). +- Re-applying an unchanged schedule is a no-op: it records no event and keeps + `next_fire_at` and its jitter. Only a `spec` or `jitter_seconds` change + moves the next fire, and `ScheduleUpdated.changed_fields` lists only fields + that changed, as Workflow 2.24.0 does + ([#1147](https://github.com/durable-workflow/server/issues/1147)). +- Operator metrics report `runs.replay_blocked`, `oldest_replay_blocked_at` + and `max_replay_blocked_age_ms`, and health has an advisory + `replay_blocked_runs` check that warns while any open run cannot replay + ([#1154](https://github.com/durable-workflow/server/issues/1154)). + +## Known limitations + +The [3.3.0 known limitations](3.3.0.md#known-limitations) still apply. +On MySQL, `json` columns can still round doubles +([#1016](https://github.com/durable-workflow/server/issues/1016)); that fix is +planned for 3.7.0 with a MySQL-only schema upgrade.