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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ to docs, or any other relevant information.
payloads, and typed argument decoding through the client's data converter.
* Added the experimental `WorkerOptions::patch_activation_callback` option for controlling whether
newly introduced patches activate during rolling deployments.
* `WorkflowContext::random` and `WorkflowContext::uuid4` for deterministic randomness in workflow.
* `ChildWorkflowOptions::builder` and `ChildWorkflowOptions::workflow_id` for constructing
child workflow options.

### Breaking Changes
* `WorkflowExecution::search_attributes`, `WorkflowExecutionDescription::search_attributes`,
Expand Down Expand Up @@ -111,6 +114,12 @@ to docs, or any other relevant information.
recover. A deterministically-oversized completion now retries per its retry policy rather than
failing fast. Tune warn thresholds via `PayloadLimitsOptions`. Opt out of worker error enforcement
with `WorkerOptions::disable_payload_error_limit`.
* `WorkflowContext::random_seed()` and `SyncWorkflowContext::random_seed()` have been removed.
Use `random::<T>()` or `uuid4()` for deterministic workflow randomness instead.
* `ChildWorkflowOptions::workflow_id` is now `Option<String>`. Wrap explicit IDs in `Some(...)`;
when omitted, the parent workflow generates a UUID child workflow ID.
* `ChildWorkflowOptions` is now tagged with `#[non_exhaustive]` so additional fields will not be breaking
changes. Users should switch to `ChildWorkflowOptions::builder()` for constructing these options.

### Fixed
* Workflow tasks no longer livelock when a burst of ready async operations exhausts Tokio's
Expand Down
166 changes: 64 additions & 102 deletions crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,7 @@ impl HappyParent {
#[run(name = "parent_wf")]
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
let started = ctx
.start_child_workflow(
ChildWf::run,
(),
ChildWorkflowOptions {
workflow_id: "child-1".to_owned(),
..Default::default()
},
)
.start_child_workflow(ChildWf::run, (), ChildWorkflowOptions::default())
.await
.expect("Child should start OK");
started.result().await?;
Expand All @@ -102,15 +95,19 @@ async fn child_workflow_happy_path() {
worker.register_workflow::<ChildWf>().unwrap();

let task_queue = starter.get_task_queue().to_owned();
worker
.submit_wf(
PARENT_WF_TYPE.to_owned(),
vec![],
let handle = worker
.submit_workflow(
HappyParent::run,
(),
WorkflowStartOptions::new(task_queue, "parent".to_string()).build(),
)
.await
.unwrap();
worker.run_until_done().await.unwrap();
handle
.fetch_history_and_replay(worker.inner_mut())
.await
.unwrap();
}

#[workflow]
Expand All @@ -126,12 +123,11 @@ impl AbandonedChildBugReproParent {
.start_child_workflow(
AbandonedChildBugReproChild::run,
(),
ChildWorkflowOptions {
workflow_id: "abandoned-child".to_owned(),
parent_close_policy: ParentClosePolicy::Abandon,
cancel_type: ChildWorkflowCancellationType::Abandon,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id("abandoned-child".to_owned())
.parent_close_policy(ParentClosePolicy::Abandon)
.cancel_type(ChildWorkflowCancellationType::Abandon)
.build(),
)
.await
.expect("Child should start OK");
Expand Down Expand Up @@ -217,12 +213,11 @@ impl AbandonedChildResolvesPostCancelParent {
.start_child_workflow(
AbandonedChildResolvesPostCancelChild::run,
(),
ChildWorkflowOptions {
workflow_id: "abandoned-child-resolve-post-cancel".to_owned(),
parent_close_policy: ParentClosePolicy::Abandon,
cancel_type: ChildWorkflowCancellationType::Abandon,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id("abandoned-child-resolve-post-cancel".to_owned())
.parent_close_policy(ParentClosePolicy::Abandon)
.cancel_type(ChildWorkflowCancellationType::Abandon)
.build(),
)
.await
.expect("Child should start OK");
Expand Down Expand Up @@ -323,11 +318,10 @@ impl CancelledChildGetsReasonParent {
.start_child_workflow(
CancelledChildGetsReasonChild::run,
(),
ChildWorkflowOptions {
workflow_id: format!("{}-child", ctx.task_queue()),
cancel_type: ChildWorkflowCancellationType::WaitCancellationRequested,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(format!("{}-child", ctx.task_queue()))
.cancel_type(ChildWorkflowCancellationType::WaitCancellationRequested)
.build(),
)
.await
.expect("Child should start OK");
Expand Down Expand Up @@ -390,10 +384,7 @@ impl SignalChildWorkflowWf {
.start_child_workflow(
UnusedChildWf::run,
(),
ChildWorkflowOptions {
workflow_id: "child-id-1".to_string(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("child-id-1".to_string()),
)
.await
.expect("Child should get started");
Expand Down Expand Up @@ -475,11 +466,10 @@ impl ParentCancelsChildWf {
.start_child_workflow(
UntypedWorkflow::new("child"),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: "child-id-1".to_string(),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id("child-id-1".to_string())
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
)
.await
.expect("Child should get started");
Expand Down Expand Up @@ -519,11 +509,10 @@ impl RuntimeParentCancelsChildWf {
.start_child_workflow(
GrandchildCancelled::run,
(),
ChildWorkflowOptions {
workflow_id: format!("{}-runtime-cancelled-child", ctx.task_queue()),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(format!("{}-runtime-cancelled-child", ctx.task_queue()))
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
)
.await
.expect("child should start");
Expand Down Expand Up @@ -592,11 +581,10 @@ impl PropagatesChildCancellationWf {
.start_child_workflow(
GrandchildCancelled::run,
(),
ChildWorkflowOptions {
workflow_id: format!("{}-grandchild", ctx.task_queue()),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(format!("{}-grandchild", ctx.task_queue()))
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
)
.await
.expect("grandchild should start");
Expand All @@ -619,10 +607,7 @@ impl GrandchildCancellationWf {
.start_child_workflow(
PropagatesChildCancellationWf::run,
(),
ChildWorkflowOptions {
workflow_id: child_workflow_id.clone(),
..Default::default()
},
ChildWorkflowOptions::workflow_id(child_workflow_id.clone()),
)
.await?;
let err = started.result().await.expect_err("child should fail");
Expand Down Expand Up @@ -812,12 +797,11 @@ impl PassChildWorkflowSummaryToMetadata {
ctx.start_child_workflow(
UntypedWorkflow::new("child"),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: child_wf_id,
static_summary: Some("child summary".to_string()),
static_details: Some("child details".to_string()),
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(child_wf_id)
.static_summary("child summary".to_string())
.static_details("child details".to_string())
.build(),
)
.await?;
Ok(())
Expand Down Expand Up @@ -917,10 +901,7 @@ impl ParentWf {
.start_child_workflow(
UntypedWorkflow::new("child"),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: "child-id-1".to_string(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("child-id-1".to_string()),
)
.await;
if let Expectation::StartFailure = expectation {
Expand Down Expand Up @@ -1035,10 +1016,7 @@ impl CancelBeforeSendWf {
let start = ctx.start_child_workflow(
UntypedWorkflow::new("child"),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: workflow_id.to_string(),
..Default::default()
},
ChildWorkflowOptions::workflow_id(workflow_id.to_string()),
);
start.cancel();
match start.await {
Expand Down Expand Up @@ -1134,11 +1112,10 @@ impl CancelChildBeforeStartedCannedWf {
let start = ctx.start_child_workflow(
UntypedWorkflow::new("child"),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: "child-id-1".to_string(),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id("child-id-1".to_string())
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
);
ctx.cancelled().await;
start.cancel();
Expand Down Expand Up @@ -1183,11 +1160,10 @@ impl CancelChildBeforeStartedParent {
let started = ctx.start_child_workflow(
AbandonedChildBugReproChild::run,
(),
ChildWorkflowOptions {
workflow_id: "cancel-before-started-child".to_owned(),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id("cancel-before-started-child".to_owned())
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
);

ctx.state(|wf| wf.barr.notify_one());
Expand Down Expand Up @@ -1279,10 +1255,7 @@ impl UntypedHappyParent {
.start_child_workflow(
UntypedWorkflow::new(CHILD_WF_TYPE),
RawValue::new(vec![]),
ChildWorkflowOptions {
workflow_id: "untyped-child-1".to_owned(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("untyped-child-1".to_owned()),
)
.await?;
started.result().await?;
Expand Down Expand Up @@ -1373,10 +1346,7 @@ impl ChildStartSerializationFailParent {
.start_child_workflow(
UnserializableStartInputChild::run,
AlwaysFailsSerialize,
ChildWorkflowOptions {
workflow_id: "unserializable-child".to_owned(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("unserializable-child".to_owned()),
)
.await;
assert_matches!(result, Err(ChildWorkflowStartError::Serialization(_)));
Expand Down Expand Up @@ -1421,10 +1391,7 @@ impl ChildSignalSerializationFailParent {
.start_child_workflow(
UnserializableSignalChild::run,
(),
ChildWorkflowOptions {
workflow_id: "signal-ser-fail-child".to_owned(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("signal-ser-fail-child".to_owned()),
)
.await?;

Expand Down Expand Up @@ -1489,10 +1456,7 @@ impl UnitChildParentWf {
.start_child_workflow(
UnitChildWf::run,
(),
ChildWorkflowOptions {
workflow_id: "child-id-1".to_string(),
..Default::default()
},
ChildWorkflowOptions::workflow_id("child-id-1".to_string()),
)
.await?;
started.result().await?;
Expand Down Expand Up @@ -1525,11 +1489,10 @@ impl CancelResultFutureParent {
.start_child_workflow(
CancelledChildGetsReasonChild::run,
(),
ChildWorkflowOptions {
workflow_id: format!("{}-child", ctx.task_queue()),
cancel_type: ChildWorkflowCancellationType::WaitCancellationCompleted,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(format!("{}-child", ctx.task_queue()))
.cancel_type(ChildWorkflowCancellationType::WaitCancellationCompleted)
.build(),
)
.await?;

Expand Down Expand Up @@ -1608,11 +1571,10 @@ impl CancelExternalThenChildParent {
.start_child_workflow(
CancelledChildGetsReasonChild::run,
(),
ChildWorkflowOptions {
workflow_id: format!("{}-child", ctx.task_queue()),
cancel_type: ChildWorkflowCancellationType::WaitCancellationRequested,
..Default::default()
},
ChildWorkflowOptions::builder()
.workflow_id(format!("{}-child", ctx.task_queue()))
.cancel_type(ChildWorkflowCancellationType::WaitCancellationRequested)
.build(),
)
.await
.expect("Child should start OK");
Expand Down
Loading
Loading