@temporalio/core-bridge 1.1.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/Cargo.lock +765 -128
  2. package/Cargo.toml +2 -2
  3. package/common.js +7 -3
  4. package/index.d.ts +118 -5
  5. package/index.js +2 -6
  6. package/package.json +2 -3
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/releases/x86_64-apple-darwin/index.node +0 -0
  10. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  11. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  12. package/scripts/build.js +4 -3
  13. package/sdk-core/.buildkite/docker/Dockerfile +2 -1
  14. package/sdk-core/.buildkite/pipeline.yml +2 -0
  15. package/sdk-core/.cargo/config.toml +1 -1
  16. package/sdk-core/ARCHITECTURE.md +2 -2
  17. package/sdk-core/README.md +12 -0
  18. package/sdk-core/bridge-ffi/Cargo.toml +2 -2
  19. package/sdk-core/bridge-ffi/src/lib.rs +2 -2
  20. package/sdk-core/client/Cargo.toml +7 -5
  21. package/sdk-core/client/src/lib.rs +354 -226
  22. package/sdk-core/client/src/metrics.rs +13 -11
  23. package/sdk-core/client/src/raw.rs +352 -107
  24. package/sdk-core/client/src/retry.rs +188 -147
  25. package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
  26. package/sdk-core/core/Cargo.toml +28 -15
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +98 -33
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
  29. package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
  30. package/sdk-core/core/src/core_tests/workers.rs +3 -2
  31. package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
  32. package/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  33. package/sdk-core/core/src/lib.rs +62 -28
  34. package/sdk-core/core/src/pollers/mod.rs +2 -0
  35. package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
  36. package/sdk-core/core/src/replay/mod.rs +3 -3
  37. package/sdk-core/core/src/retry_logic.rs +10 -9
  38. package/sdk-core/core/src/telemetry/metrics.rs +48 -39
  39. package/sdk-core/core/src/telemetry/mod.rs +46 -12
  40. package/sdk-core/core/src/telemetry/prometheus_server.rs +17 -13
  41. package/sdk-core/core/src/test_help/mod.rs +18 -8
  42. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
  44. package/sdk-core/core/src/worker/activities.rs +6 -12
  45. package/sdk-core/core/src/worker/client/mocks.rs +1 -0
  46. package/sdk-core/core/src/worker/client.rs +193 -64
  47. package/sdk-core/core/src/worker/mod.rs +14 -19
  48. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
  49. package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
  50. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
  51. package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
  52. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
  53. package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
  54. package/sdk-core/core/src/worker/workflow/mod.rs +62 -58
  55. package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
  56. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
  57. package/sdk-core/core-api/Cargo.toml +3 -3
  58. package/sdk-core/core-api/src/errors.rs +3 -11
  59. package/sdk-core/core-api/src/worker.rs +7 -0
  60. package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
  61. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
  62. package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
  63. package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
  64. package/sdk-core/protos/api_upstream/Makefile +2 -2
  65. package/sdk-core/protos/api_upstream/buf.yaml +1 -0
  66. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
  67. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
  68. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
  69. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
  70. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
  73. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
  74. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
  75. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
  80. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
  81. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
  82. package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
  84. package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
  85. package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  86. package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  87. package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  88. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  89. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  90. package/sdk-core/sdk/Cargo.toml +2 -2
  91. package/sdk-core/sdk/src/lib.rs +2 -2
  92. package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
  93. package/sdk-core/sdk/src/workflow_context.rs +30 -6
  94. package/sdk-core/sdk/src/workflow_future.rs +4 -4
  95. package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
  96. package/sdk-core/sdk-core-protos/build.rs +9 -1
  97. package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
  98. package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
  99. package/sdk-core/test-utils/Cargo.toml +3 -3
  100. package/sdk-core/test-utils/src/canned_histories.rs +58 -0
  101. package/sdk-core/test-utils/src/lib.rs +35 -12
  102. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  103. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
  104. package/sdk-core/tests/integ_tests/polling_tests.rs +2 -1
  105. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -5
  106. package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  107. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
  108. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  109. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
  110. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +2 -6
  111. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
  112. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
  113. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
  114. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +8 -2
  115. package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
  116. package/sdk-core/tests/load_tests.rs +2 -1
  117. package/sdk-core/tests/main.rs +17 -0
  118. package/sdk-core/tests/runner.rs +93 -0
  119. package/src/conversions.rs +157 -94
  120. package/src/helpers.rs +190 -0
  121. package/src/lib.rs +10 -912
  122. package/src/runtime.rs +436 -0
  123. package/src/testing.rs +67 -0
  124. package/src/worker.rs +465 -0
@@ -25,8 +25,8 @@ use crate::{
25
25
  },
26
26
  worker::{
27
27
  activities::{DispatchOrTimeoutLA, LACompleteAction, LocalActivityManager},
28
- client::{should_swallow_net_error, WorkerClientBag},
29
- workflow::{LocalResolution, Workflows},
28
+ client::WorkerClient,
29
+ workflow::{LocalResolution, WorkflowBasics, Workflows},
30
30
  },
31
31
  ActivityHeartbeat, CompleteActivityError, PollActivityError, PollWfError, WorkerTrait,
32
32
  };
@@ -50,14 +50,10 @@ use temporal_sdk_core_protos::{
50
50
  };
51
51
  use tokio_util::sync::CancellationToken;
52
52
 
53
- #[cfg(test)]
54
- use crate::worker::client::WorkerClient;
55
- use crate::worker::workflow::WorkflowBasics;
56
-
57
53
  /// A worker polls on a certain task queue
58
54
  pub struct Worker {
59
55
  config: WorkerConfig,
60
- wf_client: Arc<WorkerClientBag>,
56
+ wf_client: Arc<dyn WorkerClient>,
61
57
 
62
58
  /// Manages all workflows and WFT processing
63
59
  workflows: Workflows,
@@ -156,7 +152,7 @@ impl Worker {
156
152
  pub(crate) fn new(
157
153
  config: WorkerConfig,
158
154
  sticky_queue_name: Option<String>,
159
- client: Arc<WorkerClientBag>,
155
+ client: Arc<dyn WorkerClient>,
160
156
  metrics: MetricsContext,
161
157
  ) -> Self {
162
158
  info!(task_queue = %config.task_queue, "Initializing worker");
@@ -228,13 +224,13 @@ impl Worker {
228
224
 
229
225
  #[cfg(test)]
230
226
  pub(crate) fn new_test(config: WorkerConfig, client: impl WorkerClient + 'static) -> Self {
231
- Self::new(config, None, Arc::new(client.into()), Default::default())
227
+ Self::new(config, None, Arc::new(client), Default::default())
232
228
  }
233
229
 
234
230
  pub(crate) fn new_with_pollers(
235
231
  config: WorkerConfig,
236
232
  sticky_queue_name: Option<String>,
237
- client: Arc<WorkerClientBag>,
233
+ client: Arc<dyn WorkerClient>,
238
234
  wft_stream: impl Stream<Item = Result<ValidPollWFTQResponse, tonic::Status>> + Send + 'static,
239
235
  act_poller: Option<BoxedActPoller>,
240
236
  metrics: MetricsContext,
@@ -266,6 +262,8 @@ impl Worker {
266
262
  max_outstanding_wfts: config.max_outstanding_workflow_tasks,
267
263
  shutdown_token: shutdown_token.child_token(),
268
264
  metrics,
265
+ namespace: config.namespace.clone(),
266
+ task_queue: config.task_queue.clone(),
269
267
  },
270
268
  sticky_queue_name.map(|sq| StickyExecutionAttributes {
271
269
  worker_task_queue: Some(TaskQueue {
@@ -273,7 +271,10 @@ impl Worker {
273
271
  kind: TaskQueueKind::Sticky as i32,
274
272
  }),
275
273
  schedule_to_start_timeout: Some(
276
- config.sticky_queue_schedule_to_start_timeout.into(),
274
+ config
275
+ .sticky_queue_schedule_to_start_timeout
276
+ .try_into()
277
+ .expect("timeout fits into proto"),
277
278
  ),
278
279
  }),
279
280
  client,
@@ -422,20 +423,14 @@ impl Worker {
422
423
  }
423
424
 
424
425
  if let Some(atm) = &self.at_task_mgr {
425
- match atm.complete(task_token, status, &**self.wf_client).await {
426
- Err(CompleteActivityError::TonicError(e)) if should_swallow_net_error(&e) => {
427
- warn!(error=?e, "Network error while completing activity");
428
- Ok(())
429
- }
430
- o => o,
431
- }
426
+ atm.complete(task_token, status, &*self.wf_client).await;
432
427
  } else {
433
428
  error!(
434
429
  "Tried to complete activity {} on a worker that does not have an activity manager",
435
430
  task_token
436
431
  );
437
- Ok(())
438
432
  }
433
+ Ok(())
439
434
  }
440
435
 
441
436
  #[instrument(level = "debug", skip(self), fields(run_id))]
@@ -45,6 +45,9 @@ impl DrivenWorkflow {
45
45
  .workflow_execution_timeout
46
46
  .clone()
47
47
  .try_into_or_none(),
48
+ memo: attribs.memo.clone(),
49
+ search_attrs: attribs.search_attributes.clone(),
50
+ retry_policy: attribs.retry_policy.clone(),
48
51
  };
49
52
  self.send_job(start_workflow_from_attribs(attribs, workflow_id, randomness_seed).into());
50
53
  self.started_attrs = Some(started_info);
@@ -1,6 +1,6 @@
1
1
  use crate::{
2
2
  replay::{HistoryInfo, TestHistoryBuilder},
3
- worker::client::WorkerClientBag,
3
+ worker::client::WorkerClient,
4
4
  };
5
5
  use futures::{future::BoxFuture, stream, stream::BoxStream, FutureExt, Stream, StreamExt};
6
6
  use std::{
@@ -42,7 +42,7 @@ impl Debug for HistoryUpdate {
42
42
 
43
43
  pub struct HistoryPaginator {
44
44
  // Potentially this could actually be a ref w/ lifetime here
45
- client: Arc<WorkerClientBag>,
45
+ client: Arc<dyn WorkerClient>,
46
46
  event_queue: VecDeque<HistoryEvent>,
47
47
  wf_id: String,
48
48
  run_id: String,
@@ -82,7 +82,7 @@ impl HistoryPaginator {
82
82
  wf_id: String,
83
83
  run_id: String,
84
84
  next_page_token: impl Into<NextPageToken>,
85
- client: Arc<WorkerClientBag>,
85
+ client: Arc<dyn WorkerClient>,
86
86
  ) -> Self {
87
87
  let next_page_token = next_page_token.into();
88
88
  let (event_queue, final_events) =
@@ -397,7 +397,7 @@ pub mod tests {
397
397
  "wfid".to_string(),
398
398
  "runid".to_string(),
399
399
  vec![2], // Start at page "2"
400
- Arc::new(mock_client.into()),
400
+ Arc::new(mock_client),
401
401
  ),
402
402
  prev_started,
403
403
  );
@@ -442,7 +442,7 @@ pub mod tests {
442
442
  "runid".to_string(),
443
443
  // A cache miss means we'll try to fetch from start
444
444
  NextPageToken::FetchFromStart,
445
- Arc::new(mock_client.into()),
445
+ Arc::new(mock_client),
446
446
  ),
447
447
  1,
448
448
  );
@@ -7,7 +7,8 @@ use std::convert::{TryFrom, TryInto};
7
7
  use temporal_sdk_core_protos::{
8
8
  coresdk::{
9
9
  child_workflow::{
10
- self as wfr, child_workflow_result::Status as ChildWorkflowStatus, ChildWorkflowResult,
10
+ self as wfr, child_workflow_result::Status as ChildWorkflowStatus,
11
+ ChildWorkflowCancellationType, ChildWorkflowResult,
11
12
  },
12
13
  workflow_activation::{
13
14
  resolve_child_workflow_execution_start, ResolveChildWorkflowExecution,
@@ -17,7 +18,7 @@ use temporal_sdk_core_protos::{
17
18
  workflow_commands::StartChildWorkflowExecution,
18
19
  },
19
20
  temporal::api::{
20
- command::v1::Command,
21
+ command::v1::{Command, RequestCancelExternalWorkflowExecutionCommandAttributes},
21
22
  common::v1::{Payload, Payloads, WorkflowExecution, WorkflowType},
22
23
  enums::v1::{
23
24
  CommandType, EventType, RetryState, StartChildWorkflowExecutionFailedCause, TimeoutType,
@@ -26,8 +27,7 @@ use temporal_sdk_core_protos::{
26
27
  history::v1::{
27
28
  history_event, ChildWorkflowExecutionCompletedEventAttributes,
28
29
  ChildWorkflowExecutionFailedEventAttributes,
29
- ChildWorkflowExecutionStartedEventAttributes,
30
- ChildWorkflowExecutionTimedOutEventAttributes, HistoryEvent,
30
+ ChildWorkflowExecutionStartedEventAttributes, HistoryEvent,
31
31
  StartChildWorkflowExecutionFailedEventAttributes,
32
32
  },
33
33
  },
@@ -41,17 +41,32 @@ fsm! {
41
41
 
42
42
  Created --(Schedule, on_schedule) --> StartCommandCreated;
43
43
  StartCommandCreated --(CommandStartChildWorkflowExecution) --> StartCommandCreated;
44
- StartCommandCreated --(StartChildWorkflowExecutionInitiated(i64), shared on_start_child_workflow_execution_initiated) --> StartEventRecorded;
44
+ StartCommandCreated --(StartChildWorkflowExecutionInitiated(i64),
45
+ shared on_start_child_workflow_execution_initiated) --> StartEventRecorded;
45
46
  StartCommandCreated --(Cancel, shared on_cancelled) --> Cancelled;
46
47
 
47
- StartEventRecorded --(ChildWorkflowExecutionStarted(ChildWorkflowExecutionStartedEvent), shared on_child_workflow_execution_started) --> Started;
48
- StartEventRecorded --(StartChildWorkflowExecutionFailed(StartChildWorkflowExecutionFailedCause), on_start_child_workflow_execution_failed) --> StartFailed;
49
-
50
- Started --(ChildWorkflowExecutionCompleted(Option<Payloads>), on_child_workflow_execution_completed) --> Completed;
51
- Started --(ChildWorkflowExecutionFailed(ChildWorkflowExecutionFailedEventAttributes), shared on_child_workflow_execution_failed) --> Failed;
52
- Started --(ChildWorkflowExecutionTimedOut(i32), shared on_child_workflow_execution_timed_out) --> TimedOut;
53
- Started --(ChildWorkflowExecutionCancelled, shared on_child_workflow_execution_cancelled) --> Cancelled;
54
- Started --(ChildWorkflowExecutionTerminated, shared on_child_workflow_execution_terminated) --> Terminated;
48
+ StartEventRecorded --(ChildWorkflowExecutionStarted(ChildWorkflowExecutionStartedEvent),
49
+ shared on_child_workflow_execution_started) --> Started;
50
+ StartEventRecorded --(StartChildWorkflowExecutionFailed(StartChildWorkflowExecutionFailedCause),
51
+ on_start_child_workflow_execution_failed) --> StartFailed;
52
+
53
+ Started --(ChildWorkflowExecutionCompleted(Option<Payloads>),
54
+ on_child_workflow_execution_completed) --> Completed;
55
+ Started --(ChildWorkflowExecutionFailed(ChildWorkflowExecutionFailedEventAttributes),
56
+ shared on_child_workflow_execution_failed) --> Failed;
57
+ Started --(ChildWorkflowExecutionTimedOut(RetryState),
58
+ shared on_child_workflow_execution_timed_out) --> TimedOut;
59
+ Started --(ChildWorkflowExecutionCancelled,
60
+ on_child_workflow_execution_cancelled) --> Cancelled;
61
+ Started --(ChildWorkflowExecutionTerminated,
62
+ shared on_child_workflow_execution_terminated) --> Terminated;
63
+ // If cancelled after started, we need to issue a cancel external workflow command, and then
64
+ // the child workflow will resolve somehow, so we want to go back to started and wait for that
65
+ // resolution.
66
+ Started --(Cancel, shared on_cancelled) --> Started;
67
+ // Abandon & try cancel modes may immediately move to cancelled
68
+ Started --(Cancel, shared on_cancelled) --> Cancelled;
69
+ Started --(CommandRequestCancelExternalWorkflowExecution) --> Started;
55
70
 
56
71
  // Ignore any spurious cancellations after resolution
57
72
  Cancelled --(Cancel) --> Cancelled;
@@ -74,11 +89,13 @@ pub(super) enum ChildWorkflowCommand {
74
89
  #[display(fmt = "Fail")]
75
90
  Fail(Failure),
76
91
  #[display(fmt = "Cancel")]
77
- Cancel(Failure),
92
+ Cancel,
78
93
  #[display(fmt = "StartFail")]
79
94
  StartFail(StartChildWorkflowExecutionFailedCause),
80
95
  #[display(fmt = "StartCancel")]
81
96
  StartCancel(Failure),
97
+ #[display(fmt = "CancelAfterStarted")]
98
+ IssueCancelAfterStarted { reason: String },
82
99
  }
83
100
 
84
101
  #[derive(Default, Clone)]
@@ -137,10 +154,7 @@ impl StartCommandCreated {
137
154
  )),
138
155
  ..Default::default()
139
156
  })),
140
- failure_info: failure_info_from_state(
141
- state.clone(),
142
- RetryState::NonRetryableFailure as i32,
143
- ),
157
+ failure_info: failure_info_from_state(&state, RetryState::NonRetryableFailure),
144
158
  ..Default::default()
145
159
  })],
146
160
  Cancelled::default(),
@@ -188,7 +202,7 @@ pub(super) struct StartFailed {}
188
202
  pub(super) struct Started {}
189
203
 
190
204
  impl Started {
191
- pub(super) fn on_child_workflow_execution_completed(
205
+ fn on_child_workflow_execution_completed(
192
206
  self,
193
207
  result: Option<Payloads>,
194
208
  ) -> ChildWorkflowMachineTransition<Completed> {
@@ -197,7 +211,7 @@ impl Started {
197
211
  Completed::default(),
198
212
  )
199
213
  }
200
- pub(super) fn on_child_workflow_execution_failed(
214
+ fn on_child_workflow_execution_failed(
201
215
  self,
202
216
  state: SharedState,
203
217
  attrs: ChildWorkflowExecutionFailedEventAttributes,
@@ -205,17 +219,17 @@ impl Started {
205
219
  ChildWorkflowMachineTransition::ok(
206
220
  vec![ChildWorkflowCommand::Fail(Failure {
207
221
  message: "Child Workflow execution failed".to_owned(),
222
+ failure_info: failure_info_from_state(&state, attrs.retry_state()),
208
223
  cause: attrs.failure.map(Box::new),
209
- failure_info: failure_info_from_state(state, attrs.retry_state),
210
224
  ..Default::default()
211
225
  })],
212
226
  Failed::default(),
213
227
  )
214
228
  }
215
- pub(super) fn on_child_workflow_execution_timed_out(
229
+ fn on_child_workflow_execution_timed_out(
216
230
  self,
217
231
  state: SharedState,
218
- retry_state: i32,
232
+ retry_state: RetryState,
219
233
  ) -> ChildWorkflowMachineTransition<TimedOut> {
220
234
  ChildWorkflowMachineTransition::ok(
221
235
  vec![ChildWorkflowCommand::Fail(Failure {
@@ -230,37 +244,16 @@ impl Started {
230
244
  )),
231
245
  ..Default::default()
232
246
  })),
233
- failure_info: failure_info_from_state(state, retry_state),
247
+ failure_info: failure_info_from_state(&state, retry_state),
234
248
  ..Default::default()
235
249
  })],
236
250
  TimedOut::default(),
237
251
  )
238
252
  }
239
- pub(super) fn on_child_workflow_execution_cancelled(
240
- self,
241
- state: SharedState,
242
- ) -> ChildWorkflowMachineTransition<Cancelled> {
243
- ChildWorkflowMachineTransition::ok(
244
- vec![ChildWorkflowCommand::Cancel(Failure {
245
- message: "Child Workflow execution cancelled".to_owned(),
246
- cause: Some(Box::new(Failure {
247
- failure_info: Some(FailureInfo::CanceledFailureInfo(
248
- failure::CanceledFailureInfo {
249
- ..Default::default()
250
- },
251
- )),
252
- ..Default::default()
253
- })),
254
- failure_info: failure_info_from_state(
255
- state,
256
- RetryState::NonRetryableFailure as i32,
257
- ),
258
- ..Default::default()
259
- })],
260
- Cancelled::default(),
261
- )
253
+ fn on_child_workflow_execution_cancelled(self) -> ChildWorkflowMachineTransition<Cancelled> {
254
+ ChildWorkflowMachineTransition::ok(vec![ChildWorkflowCommand::Cancel], Cancelled::default())
262
255
  }
263
- pub(super) fn on_child_workflow_execution_terminated(
256
+ fn on_child_workflow_execution_terminated(
264
257
  self,
265
258
  state: SharedState,
266
259
  ) -> ChildWorkflowMachineTransition<Terminated> {
@@ -274,15 +267,29 @@ impl Started {
274
267
  )),
275
268
  ..Default::default()
276
269
  })),
277
- failure_info: failure_info_from_state(
278
- state,
279
- RetryState::NonRetryableFailure as i32,
280
- ),
270
+ failure_info: failure_info_from_state(&state, RetryState::NonRetryableFailure),
281
271
  ..Default::default()
282
272
  })],
283
273
  Terminated::default(),
284
274
  )
285
275
  }
276
+ fn on_cancelled(
277
+ self,
278
+ state: SharedState,
279
+ ) -> ChildWorkflowMachineTransition<StartedOrCancelled> {
280
+ let dest = match state.cancel_type {
281
+ ChildWorkflowCancellationType::Abandon | ChildWorkflowCancellationType::TryCancel => {
282
+ StartedOrCancelled::Cancelled(Default::default())
283
+ }
284
+ _ => StartedOrCancelled::Started(Default::default()),
285
+ };
286
+ TransitionResult::ok(
287
+ [ChildWorkflowCommand::IssueCancelAfterStarted {
288
+ reason: "Parent workflow requested cancel".to_string(),
289
+ }],
290
+ dest,
291
+ )
292
+ }
286
293
  }
287
294
 
288
295
  #[derive(Default, Clone)]
@@ -301,6 +308,7 @@ pub(super) struct SharedState {
301
308
  run_id: String,
302
309
  workflow_type: String,
303
310
  cancelled_before_sent: bool,
311
+ cancel_type: ChildWorkflowCancellationType,
304
312
  }
305
313
 
306
314
  /// Creates a new child workflow state machine and a command to start it on the server.
@@ -322,6 +330,7 @@ impl ChildWorkflowMachine {
322
330
  workflow_id: attribs.workflow_id.clone(),
323
331
  workflow_type: attribs.workflow_type.clone(),
324
332
  namespace: attribs.namespace.clone(),
333
+ cancel_type: attribs.cancellation_type(),
325
334
  ..Default::default()
326
335
  },
327
336
  };
@@ -333,6 +342,33 @@ impl ChildWorkflowMachine {
333
342
  };
334
343
  (s, cmd)
335
344
  }
345
+
346
+ fn resolve_cancelled_msg(&self) -> ResolveChildWorkflowExecution {
347
+ let failure = Failure {
348
+ message: "Child Workflow execution cancelled".to_owned(),
349
+ cause: Some(Box::new(Failure {
350
+ failure_info: Some(FailureInfo::CanceledFailureInfo(
351
+ failure::CanceledFailureInfo {
352
+ ..Default::default()
353
+ },
354
+ )),
355
+ ..Default::default()
356
+ })),
357
+ failure_info: failure_info_from_state(
358
+ &self.shared_state,
359
+ RetryState::NonRetryableFailure,
360
+ ),
361
+ ..Default::default()
362
+ };
363
+ ResolveChildWorkflowExecution {
364
+ seq: self.shared_state.lang_sequence_number,
365
+ result: Some(ChildWorkflowResult {
366
+ status: Some(ChildWorkflowStatus::Cancelled(wfr::Cancellation {
367
+ failure: Some(failure),
368
+ })),
369
+ }),
370
+ }
371
+ }
336
372
  }
337
373
 
338
374
  impl TryFrom<HistoryEvent> for ChildWorkflowMachineEvents {
@@ -415,12 +451,10 @@ impl TryFrom<HistoryEvent> for ChildWorkflowMachineEvents {
415
451
  }
416
452
  Some(EventType::ChildWorkflowExecutionTimedOut) => {
417
453
  if let Some(
418
- history_event::Attributes::ChildWorkflowExecutionTimedOutEventAttributes(
419
- ChildWorkflowExecutionTimedOutEventAttributes { retry_state, .. },
420
- ),
454
+ history_event::Attributes::ChildWorkflowExecutionTimedOutEventAttributes(atts),
421
455
  ) = e.attributes
422
456
  {
423
- Self::ChildWorkflowExecutionTimedOut(retry_state)
457
+ Self::ChildWorkflowExecutionTimedOut(atts.retry_state())
424
458
  } else {
425
459
  return Err(WFMachinesError::Fatal(
426
460
  "ChildWorkflowExecutionTimedOut attributes were unset or malformed"
@@ -435,9 +469,10 @@ impl TryFrom<HistoryEvent> for ChildWorkflowMachineEvents {
435
469
  Self::ChildWorkflowExecutionCancelled
436
470
  }
437
471
  _ => {
438
- return Err(WFMachinesError::Fatal(
439
- "Child workflow machine does not handle this event".to_string(),
440
- ))
472
+ return Err(WFMachinesError::Fatal(format!(
473
+ "Child workflow machine does not handle this event: {:?}",
474
+ e
475
+ )))
441
476
  }
442
477
  })
443
478
  }
@@ -505,16 +540,33 @@ impl WFMachinesAdapter for ChildWorkflowMachine {
505
540
  }
506
541
  .into()]
507
542
  }
508
- ChildWorkflowCommand::Cancel(failure) => {
509
- vec![ResolveChildWorkflowExecution {
510
- seq: self.shared_state.lang_sequence_number,
511
- result: Some(ChildWorkflowResult {
512
- status: Some(ChildWorkflowStatus::Cancelled(wfr::Cancellation {
513
- failure: Some(failure),
514
- })),
515
- }),
543
+ ChildWorkflowCommand::Cancel => {
544
+ vec![self.resolve_cancelled_msg().into()]
545
+ }
546
+ ChildWorkflowCommand::IssueCancelAfterStarted { reason } => {
547
+ let mut resps = vec![];
548
+ if self.shared_state.cancel_type != ChildWorkflowCancellationType::Abandon {
549
+ resps.push(MachineResponse::NewCoreOriginatedCommand(
550
+ RequestCancelExternalWorkflowExecutionCommandAttributes {
551
+ namespace: self.shared_state.namespace.clone(),
552
+ workflow_id: self.shared_state.workflow_id.clone(),
553
+ run_id: self.shared_state.run_id.clone(),
554
+ child_workflow_only: true,
555
+ reason,
556
+ control: "".to_string(),
557
+ }
558
+ .into(),
559
+ ))
516
560
  }
517
- .into()]
561
+ // Immediately resolve abandon/trycancel modes
562
+ if matches!(
563
+ self.shared_state.cancel_type,
564
+ ChildWorkflowCancellationType::Abandon
565
+ | ChildWorkflowCancellationType::TryCancel
566
+ ) {
567
+ resps.push(self.resolve_cancelled_msg().into())
568
+ }
569
+ resps
518
570
  }
519
571
  })
520
572
  }
@@ -544,34 +596,30 @@ impl TryFrom<CommandType> for ChildWorkflowMachineEvents {
544
596
  fn try_from(c: CommandType) -> Result<Self, Self::Error> {
545
597
  Ok(match c {
546
598
  CommandType::StartChildWorkflowExecution => Self::CommandStartChildWorkflowExecution,
599
+ CommandType::RequestCancelExternalWorkflowExecution => {
600
+ Self::CommandRequestCancelExternalWorkflowExecution
601
+ }
547
602
  _ => return Err(()),
548
603
  })
549
604
  }
550
605
  }
551
606
 
552
- /// Cancellation through this machine is valid only when start child workflow command is not sent
553
- /// yet. Cancellation of an initiated child workflow is done through CancelExternal.
554
- /// All of the types besides ABANDON are treated differently.
555
607
  impl Cancellable for ChildWorkflowMachine {
556
608
  fn cancel(&mut self) -> Result<Vec<MachineResponse>, MachineError<Self::Error>> {
557
609
  let event = ChildWorkflowMachineEvents::Cancel;
558
610
  let vec = OnEventWrapper::on_event_mut(self, event)?;
559
611
  let res = vec
560
612
  .into_iter()
561
- .flat_map(|mc| match mc {
562
- ChildWorkflowCommand::StartCancel(failure) => {
563
- vec![ResolveChildWorkflowExecutionStart {
564
- seq: self.shared_state.lang_sequence_number,
565
- status: Some(resolve_child_workflow_execution_start::Status::Cancelled(
566
- ResolveChildWorkflowExecutionStartCancelled {
567
- failure: Some(failure),
568
- },
569
- )),
570
- }
571
- .into()]
613
+ .map(|mc| match mc {
614
+ c @ ChildWorkflowCommand::StartCancel(_)
615
+ | c @ ChildWorkflowCommand::IssueCancelAfterStarted { .. } => {
616
+ self.adapt_response(c, None)
572
617
  }
573
618
  x => panic!("Invalid cancel event response {:?}", x),
574
619
  })
620
+ .collect::<Result<Vec<_>, _>>()?
621
+ .into_iter()
622
+ .flatten()
575
623
  .collect();
576
624
  Ok(res)
577
625
  }
@@ -581,7 +629,7 @@ impl Cancellable for ChildWorkflowMachine {
581
629
  }
582
630
  }
583
631
 
584
- fn failure_info_from_state(state: SharedState, retry_state: i32) -> Option<FailureInfo> {
632
+ fn failure_info_from_state(state: &SharedState, retry_state: RetryState) -> Option<FailureInfo> {
585
633
  Some(FailureInfo::ChildWorkflowExecutionFailureInfo(
586
634
  failure::ChildWorkflowExecutionFailureInfo {
587
635
  namespace: state.namespace.clone(),
@@ -590,10 +638,10 @@ fn failure_info_from_state(state: SharedState, retry_state: i32) -> Option<Failu
590
638
  }),
591
639
  initiated_event_id: state.initiated_event_id,
592
640
  started_event_id: state.started_event_id,
593
- retry_state,
641
+ retry_state: retry_state as i32,
594
642
  workflow_execution: Some(WorkflowExecution {
595
643
  workflow_id: state.workflow_id.clone(),
596
- run_id: state.run_id,
644
+ run_id: state.run_id.clone(),
597
645
  }),
598
646
  },
599
647
  ))
@@ -160,8 +160,9 @@ where
160
160
  }
161
161
  } else {
162
162
  Err(WFMachinesError::Nondeterminism(format!(
163
- "Unexpected command {:?}",
164
- command_type
163
+ "Unexpected command {:?} generated by a {:?} machine",
164
+ command_type,
165
+ self.kind()
165
166
  )))
166
167
  }
167
168
  }