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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 3.2.2

- Register complete query and update argument contracts for JSON and lossless
Avro handlers. Server can admit commands for new Rust workflow runs using
the handlers' positional argument vectors.
- Keep unsupported update validators refused and preserve explicitly supplied
low-level registration metadata. Existing runs retain their original declarations.

## 3.2.1

- Add `Worker::recover_transient_outages(true)` for long-running service workers.
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "durable-workflow"
version = "3.2.1"
version = "3.2.2"
edition = "2021"
description = "Rust client and worker SDK for Durable Workflow Cloud and self-hosted Server"
license = "MIT"
Expand All @@ -14,7 +14,7 @@ categories = ["api-bindings", "asynchronous"]
include = ["/src/**", "/schema/**", "/examples/**", "/Cargo.toml", "/README.md", "/CHANGELOG.md", "/LICENSE"]

[package.metadata.durable-workflow]
product-train = "3.2.1"
product-train = "3.2.2"
compatibility-authority = "protocol-manifests"
supported-server-versions = "2.0.0"
qualified-server-version = "2.5.1"
Expand Down
86 changes: 82 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6283,6 +6283,27 @@ struct RegisteredWorkflow {
definition_fingerprint: Option<String>,
}

fn argument_vector_contracts(names: &[String]) -> Vec<Value> {
names
.iter()
.map(|name| {
json!({
"name": name,
"parameters": [{
"name": "args",
"position": 0,
"required": false,
"variadic": true,
"type": null,
"allows_null": true,
"default_available": false,
"default": null,
}],
})
})
.collect()
}

#[derive(Debug)]
struct WorkflowTaskDecision {
commands: Vec<Value>,
Expand Down Expand Up @@ -7106,11 +7127,11 @@ impl Worker {
workflow_type.clone(),
json!({
"queries": queries,
"query_contracts": [],
"query_contracts": argument_vector_contracts(&queries),
"signals": [],
"signal_contracts": [],
"updates": updates,
"update_contracts": [],
"update_contracts": argument_vector_contracts(&updates),
"update_validators": [],
}),
);
Expand Down Expand Up @@ -25706,6 +25727,49 @@ mod tests {
assert_eq!(server.request_count("/api/worker/register"), 0);
}

#[tokio::test]
async fn worker_registers_complete_json_and_lossless_handler_argument_contracts() {
let server = MockWorkerServer::start();
let client = Client::builder(server.base_url())
.timeout(Duration::from_secs(2))
.build()
.expect("client");
let mut worker = Worker::new(client, "rust-workers");
worker.register_workflow("orders", |_ctx, input| async move { Ok(input) });
worker.register_query("orders", "z-json", |_ctx, args| async move { Ok(args) });
worker.register_query_avro_value("orders", "a-avro", |_ctx, args| async move { Ok(args) });
worker.register_update("orders", "z-json", |_ctx, args| async move { Ok(args) });
worker.register_update_avro_value("orders", "a-avro", |_ctx, args| async move { Ok(args) });

worker.register().await.expect("register handler contracts");

let declaration =
&server.request_body("/api/worker/register")["workflow_command_contracts"]["orders"];
let expected_contracts = json!([
{
"name": "a-avro",
"parameters": [{
"name": "args", "position": 0, "required": false,
"variadic": true, "type": null, "allows_null": true,
"default_available": false, "default": null,
}],
},
{
"name": "z-json",
"parameters": [{
"name": "args", "position": 0, "required": false,
"variadic": true, "type": null, "allows_null": true,
"default_available": false, "default": null,
}],
},
]);
assert_eq!(declaration["queries"], json!(["a-avro", "z-json"]));
assert_eq!(declaration["query_contracts"], expected_contracts);
assert_eq!(declaration["updates"], json!(["a-avro", "z-json"]));
assert_eq!(declaration["update_contracts"], expected_contracts);
assert_eq!(declaration["update_validators"], json!([]));
}

#[tokio::test]
async fn low_level_registration_preserves_query_and_update_contracts() {
let server = MockWorkerServer::start();
Expand Down Expand Up @@ -27290,11 +27354,25 @@ mod tests {
server.request_body("/api/worker/register")["workflow_command_contracts"]["snapshot"],
json!({
"queries": ["current"],
"query_contracts": [],
"query_contracts": [{
"name": "current",
"parameters": [{
"name": "args", "position": 0, "required": false,
"variadic": true, "type": null, "allows_null": true,
"default_available": false, "default": null,
}],
}],
"signals": [],
"signal_contracts": [],
"updates": ["replace"],
"update_contracts": [],
"update_contracts": [{
"name": "replace",
"parameters": [{
"name": "args", "position": 0, "required": false,
"variadic": true, "type": null, "allows_null": true,
"default_available": false, "default": null,
}],
}],
"update_validators": [],
})
);
Expand Down
Loading