Skip to content

3.3.0

Choose a tag to compare

@github-actions github-actions released this 08 Nov 17:47
· 61 commits to main since this release
Immutable release. Only release title and notes can be modified.
2a15179

Durable Workflow Server 3.3.0.

Git tag 3.3.0 → 2a15179f29801eec9f2a2d4e6a9c5f93233f104e
Image index sha256:cb4b11bd6235a551cf51e7dc6342504fbbcef19959618b376fb5648ca00fc388 in durableworkflow/server and ghcr.io/durable-workflow/server
Release run https://github.com/durable-workflow/server/actions/runs/42460578773

Durable Workflow Server 3.3.0 (native)

Server 3.3.0 is a minor release of the native (Rust) Server. It is published
as durableworkflow/server:3.3.0 and ghcr.io/durable-workflow/server:3.3.0.
The published Compose file defaults to it. Rolling tags move only in the
separate promotion step that follows the release's qualification.

Upgrade

Schema 10 → 11 on MySQL, MariaDB and PostgreSQL. This release adds one
index to workflow_tasks, so the native schema on MySQL, MariaDB and
PostgreSQL moves from version 10 to version 11. SQLite stays at version 10
and needs no upgrade step from 3.2.x.

A server never upgrades its schema at startup. Started on a version 10
database, 3.3.0 refuses with native_schema_upgrade_required. To upgrade:

  1. Stop every native node.
  2. Back up the database.
  3. Run the 3.3.0 image's schema-upgrade once, with the same DB_*
    settings, as described in
    Native schema upgrades.
  4. Start the 3.3.0 nodes.

Databases on an earlier native schema this release knows (version 8, from
3.0.x and 3.1.x) are upgraded by the same command.

  • PostgreSQL: the upgrade builds the new index with a plain
    CREATE INDEX, which blocks writes to workflow_tasks until the build
    finishes. On a large workflow_tasks table, plan the upgrade window for it.
  • MySQL and MariaDB: DDL commits on its own there, so the upgrade marks the
    database as upgrading until it finishes. If an upgrade is interrupted,
    running schema-upgrade again resumes it.

Rolling back to 3.2.x requires restoring a backup. Once a MySQL, MariaDB
or PostgreSQL database is at version 11, a 3.2.x server refuses it with
native_schema_newer_than_binary. To go back to 3.2.x, restore the backup
taken before the upgrade.

SQLite databases stay at version 10, so 3.2.x can still open them, but 3.2.x
must not continue a condition wait opened with the occurrence deadline policy
(below). A 3.2.x server silently drops the policy fields, so a reopen of such a
wait records an ordinary per-open wait in the middle of an anchored chain.
After that, sdk-php refuses to replay the run, and 3.3.0 refuses later reopens
of the chain, even after you upgrade again; upgrading again does not repair a
chain that is already mixed. If any workflow has used the occurrence deadline
policy, roll an SQLite database back to 3.2.x only by restoring the backup
taken before the upgrade.

Unchanged: the worker protocol stays at 1.20 and the control plane at
version 2. Cluster info and worker server_capabilities add one capability,
condition_wait_occurrence_deadline.

Changes

Opt-in occurrence wall deadline for condition waits

An open_condition_wait command can opt in to one wall deadline for an
authored condition-wait occurrence, so false wake-ups no longer restart its
timeout
(sdk-php#269,
#1098).
Native advertises this as condition_wait_occurrence_deadline: true.

  • The command sets deadline_policy: "occurrence" and
    condition_wait_timeout_budget_seconds, the original timeout. Its
    timeout_seconds stays the remaining time and must be between 0 and the
    original budget. It also needs a condition_wait_occurrence_id.
  • The first open of an occurrence must author its whole budget, and fixes the
    deadline at that commit plus the budget.
  • A reopen of the same run, occurrence, condition key and definition
    fingerprint reuses the first timer's stored deadline exactly. If that
    deadline has already passed, the new timer is due at once; it never fires
    inside the completion.
  • The history records the policy and original budget on
    ConditionWaitOpened, and occurrence_deadline_at on both
    ConditionWaitOpened and the timeout's TimerScheduled.
  • Conflicts refuse the whole completion and write nothing:
    condition_wait_occurrence_mismatch, condition_wait_occurrence_timed_out
    and condition_wait_anchor_unavailable. Malformed policy fields refuse with
    invalid_condition_deadline_policy.
  • An occurrence first opened without the policy keeps its per-open timeout,
    and a later opt-in to it is refused. An occurrence opened with the policy
    must keep it on every reopen.
  • Legacy chains first opened without the policy retain their existing behavior.

SDK support is merged in sdk-php
(sdk-php#364) and
ships in a later sdk-php release; sdk-php 3.10.0 does not send the policy.
The sdk-php release that includes it must also fail closed when the
Server stops advertising condition_wait_occurrence_deadline: if an existing
anchored chain needs a reopen, the worker aborts the task without completing
it, so the history stays unchanged until a capable Server is back.
The PHP Server does not support this feature.

Empty query polls without the transition lock

A new non-waiting query poll (timeout_seconds: 0 with a poll_request_id)
that would find nothing is answered empty from one read snapshot, without
taking the transition lock and without writing anything. It does this only
while every fact of that answer holds at the snapshot's instant; otherwise it
takes the locked path as before. On MySQL and MariaDB the snapshot is an
explicit repeatable-read transaction
(server#1057,
#1097).

Bounded claim candidate reads

  • MySQL and MariaDB read ready and leased claim candidates in separate,
    bounded ranges in dispatch order, through the new scoped dispatch index
    (server#1065,
    #1085).
  • PostgreSQL reads ready and leased candidates through separate, fully
    scoped ordered ranges on the new index, with namespace, queue and task-kind
    predicates inside each range
    (server#1069,
    #1088).
  • All backends: a claim first reads one fairness batch of 10 candidates
    and tries those, reading the full 100-candidate page only when the batch
    cannot be decided or claimed. Batch boundaries and fairness order are
    unchanged
    (server#1064,
    #1092).

The candidates each claim returns, and their order, are the same as before.

First history page reuses the claimed history total

A workflow claim already holds the run's last history sequence. The first
history page and the history budget now use that value instead of reading it
again. Later pages keep the original lookup
(server#1066,
#1093).

Known limitations

  • Ready-age replay after a restart: the MariaDB restart lane once failed
    the cold-poll replay claim assertion after SIGKILL recovery. The retained
    response did not establish whether the answer was empty or a capability or
    age field was missing. Diagnostics were added; the intermittent cause is
    still under investigation
    (server#1096).