Repository navigation
4.15.0
Known inline fan-out limitation: 4.15.0 applies the ordinary request cap
(2 MiB by default) to the entire command batch during payload planning. On a
namespace without external payload storage, the published 300 × 10 KB fan-out
exits with external_payload_unavailable and leaves the run pending. Use
smaller command batches while SDK #254
and Server #1136 are
being corrected and qualified. This is separate from the over-limit HTTP 413
transport failure described below. Scoped published acceptance
passes ordinary lifecycle/deadline behavior and pending-to-completed-null
update reads; fan-out and over-limit acceptance remain open.
4.15.0
-
All workflow and run routes encode each identifier or name as one path
segment. Empty identifiers and.or..segments return
Error::InvalidPathSegmentbefore any HTTP request, including capability
discovery for cooperative cancellation. -
Cooperative cancellation now reads the optional top-level
causeof the
portable cancellation context (workflow#863, workflow#1129). A
timeout-cleanup request (cause: "timeout": the run passed its work
deadline and is now in cleanup) arrives through the existing
Error::CooperativeCancellationRequested, so existing
Error::CooperativeCancellationRequested(_)arms, such as saga
compensation, run for it unchanged. There is no newErrorvariant. Tell
the two apart with the new#[non_exhaustive]CancellationCause:
Requestedfor an ordinary request (causeabsent or"cancellation") or
Timeout. The request's cleanup deadline is its existing
cleanup_deadline_at.CancellationRequest::cause(),CancellationContext::cause()andis_timeout()
read it from the context. A context with any othercauseis refused as
Error::InvalidCooperativeCancellation. The cause is never inherited: a
descendant cancelled under the request, scoped or not, carries nocause
and is an ordinary cancellation, even when its scope origin's root context
carriescause: "timeout".CancellationContext::to_value()writescause
back exactly as read, including an explicit"cancellation", and an
ordinary context's output is unchanged.CancellationRequest::cause()derives the discriminator from the existing
context, preserving stable 4.x struct literals and exhaustive destructuring.
This parser support is experimental. Service-mode timeout-cleanup admission
and execution require the upstream Core/native implementation and separate
published-artifact qualification. -
A workflow-task completion that native Server 3.6.0 refuses as too large
(HTTP 413,limit_kind: workflow_task_completion_bytes, server#1152,
durable-workflow/.github#228) is now a typed, non-retryable outcome.
Client::complete_workflow_taskreturns the new
Error::WorkflowTaskCompletionTooLargewith the Server's limit, the encoded
request size and the Server's message, and the request is never resent. A
Workerno longer leaves the task to be redelivered into the same refusal:
it completes the task once with a non-retryablefail_workflowcommand whose
message starts withStructural limit exceeded:, so the run fails with
failure categorystructural_limitand guidance to split the fan-out, use
child workflows or continue as new. Other 413 and 5xx responses are
unchanged. The README documents the completion size limit.Known transport limitation: this typed failure requires the Server's
HTTP 413 to reach the worker. An aggregate over-limit request can currently
lose that response and return a transport error instead. Automatic
structural failure for that path is not yet qualified. The Server response
correction and published-artifact controls remain open in
the fan-out issue. -
An update whose wait ends before its handler finishes now returns
Error::UpdateStillPendinginstead ofOk(Null)(durable-workflow/.github#212).
update_workflowused to return the Server'sresult: nullfor a 202
wait_timed_outreceipt, so a pending update looked like a handler that
returned null. The error carries theupdate_id,request_id, current
run_id,update_statusand full receipt; a real null result is still
Ok(Null).update_workflow_avro_valuereturns the same error instead of a
missing_payload_envelopecodec error. -
Client::update_outcome,Client::update_outcome_avro_valueand
Client::update_outcome_receipt(andWorkflowHandle::update_outcome) read an
accepted update's outcome later by its update id, without submitting it
again (server#1131). They need a Server that advertises
update_outcome_reads(native 3.6.0 and later) and return
Error::UpdateOutcomeReadsUnavailableotherwise, before reading anything. A
still-running update returnsError::UpdateStillPendingwith a hint to read
again by update id. A failed update isError::Http422, and
Error::is_update_not_found()detects 404update_not_found. An empty,.
or..workflow id or update id is refused before any request, so a read
can't collapse onto another route. A successful answer that isn't a receipt
for the requested update (matchingupdate_idand anupdate_status), or a
non-completed receipt where an outcome was expected, returns
Error::UnrecognizedUpdateOutcomeinstead of a value. -
describe_workflowandupdate_workflow(andupdate_workflow_avro_value)
percent-encode the workflow id, and the update name, as one path segment.
Before, they were put into the path raw, so an id containing/,?or#
addressed a different route. An empty,.or..id or update name now
returnsError::InvalidPathSegmentbefore any request;..would otherwise
have described or updated another route. Found in the security review of
sdk-rust#243 (durable-workflow/.github#212). -
A
request_id_conflictrefusal from native Server 3.9.0 (server#934,
server#1191) now names the key that was sent. Native doesn't echo the key, so
Error::request_id()returnedNoneandRequestIdConflict::request_idwas
empty. The SDK now adds the sent key to the refusal body when the Server
doesn't echo it. The error is stillError::Httpwith status 409, it is sent
once and never resent, andRequestIdConflictdocuments native'sconflict
parts (name,arguments,target_or_arguments). The README describes
request IDs and thecommand_request_keyscapability. Older Servers are
unaffected. -
Replay ignores the activity cancellations a run's own close records
(durable-workflow/server#1193, durable-workflow/workflow#1117). When a run
completes, fails or continues as new, Workflow 2.28.0 (and Server with
server#1193) recordsActivityCancelledwithcancellation_reason: run_closed
for each activity it never awaited, such as aselect()loser. Replay now
leaves that activity open instead of treating the cancellation as an outcome:
a handledall()failure is no longer replaced by a lower-index member
cancelled at close. The newabandoned_activitieskey onWorkflowCompleted,
WorkflowFailedandWorkflowContinuedAsNewis accepted. Activity workers
already treat arun_closedheartbeat or late outcome (recorded: false) as
final; new tests cover it, including an abandon-policy activity that keeps
running after close.