@temporalio/core-bridge 0.14.0 → 0.16.4

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 (75) hide show
  1. package/Cargo.lock +162 -38
  2. package/Cargo.toml +3 -3
  3. package/index.d.ts +14 -1
  4. package/index.node +0 -0
  5. package/package.json +8 -5
  6. package/releases/aarch64-apple-darwin/index.node +0 -0
  7. package/releases/{x86_64-pc-windows-gnu → aarch64-unknown-linux-gnu}/index.node +0 -0
  8. package/releases/x86_64-apple-darwin/index.node +0 -0
  9. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  10. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  11. package/scripts/build.js +77 -34
  12. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  13. package/sdk-core/Cargo.toml +6 -5
  14. package/sdk-core/fsm/Cargo.toml +1 -1
  15. package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +2 -2
  16. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +8 -9
  17. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +13 -7
  18. package/sdk-core/fsm/rustfsm_trait/Cargo.toml +2 -2
  19. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +1 -1
  20. package/sdk-core/protos/local/workflow_activation.proto +6 -3
  21. package/sdk-core/sdk-core-protos/Cargo.toml +4 -4
  22. package/sdk-core/sdk-core-protos/src/lib.rs +38 -50
  23. package/sdk-core/src/core_tests/activity_tasks.rs +5 -5
  24. package/sdk-core/src/core_tests/child_workflows.rs +55 -29
  25. package/sdk-core/src/core_tests/determinism.rs +19 -9
  26. package/sdk-core/src/core_tests/mod.rs +3 -3
  27. package/sdk-core/src/core_tests/retry.rs +14 -8
  28. package/sdk-core/src/core_tests/workers.rs +1 -1
  29. package/sdk-core/src/core_tests/workflow_tasks.rs +347 -4
  30. package/sdk-core/src/errors.rs +27 -44
  31. package/sdk-core/src/lib.rs +13 -3
  32. package/sdk-core/src/machines/activity_state_machine.rs +44 -5
  33. package/sdk-core/src/machines/child_workflow_state_machine.rs +31 -11
  34. package/sdk-core/src/machines/complete_workflow_state_machine.rs +1 -1
  35. package/sdk-core/src/machines/continue_as_new_workflow_state_machine.rs +1 -1
  36. package/sdk-core/src/machines/mod.rs +18 -23
  37. package/sdk-core/src/machines/patch_state_machine.rs +8 -8
  38. package/sdk-core/src/machines/signal_external_state_machine.rs +22 -1
  39. package/sdk-core/src/machines/timer_state_machine.rs +21 -3
  40. package/sdk-core/src/machines/transition_coverage.rs +3 -3
  41. package/sdk-core/src/machines/workflow_machines.rs +11 -11
  42. package/sdk-core/src/pending_activations.rs +27 -22
  43. package/sdk-core/src/pollers/gateway.rs +15 -7
  44. package/sdk-core/src/pollers/poll_buffer.rs +6 -5
  45. package/sdk-core/src/pollers/retry.rs +153 -120
  46. package/sdk-core/src/prototype_rust_sdk/workflow_context.rs +61 -46
  47. package/sdk-core/src/prototype_rust_sdk/workflow_future.rs +13 -12
  48. package/sdk-core/src/prototype_rust_sdk.rs +17 -23
  49. package/sdk-core/src/telemetry/metrics.rs +2 -4
  50. package/sdk-core/src/telemetry/mod.rs +6 -7
  51. package/sdk-core/src/test_help/canned_histories.rs +17 -93
  52. package/sdk-core/src/test_help/history_builder.rs +61 -2
  53. package/sdk-core/src/test_help/history_info.rs +21 -2
  54. package/sdk-core/src/test_help/mod.rs +26 -34
  55. package/sdk-core/src/worker/activities/activity_heartbeat_manager.rs +246 -138
  56. package/sdk-core/src/worker/activities.rs +46 -45
  57. package/sdk-core/src/worker/config.rs +11 -0
  58. package/sdk-core/src/worker/dispatcher.rs +5 -5
  59. package/sdk-core/src/worker/mod.rs +86 -56
  60. package/sdk-core/src/workflow/driven_workflow.rs +3 -3
  61. package/sdk-core/src/workflow/history_update.rs +1 -1
  62. package/sdk-core/src/workflow/mod.rs +2 -1
  63. package/sdk-core/src/workflow/workflow_tasks/cache_manager.rs +13 -17
  64. package/sdk-core/src/workflow/workflow_tasks/concurrency_manager.rs +10 -18
  65. package/sdk-core/src/workflow/workflow_tasks/mod.rs +72 -57
  66. package/sdk-core/test_utils/Cargo.toml +1 -1
  67. package/sdk-core/test_utils/src/lib.rs +2 -2
  68. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +61 -1
  69. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +2 -2
  70. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +49 -0
  71. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +2 -2
  72. package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
  73. package/src/conversions.rs +17 -0
  74. package/src/errors.rs +0 -7
  75. package/src/lib.rs +0 -20
@@ -128,7 +128,7 @@ impl ActivityMachine {
128
128
  {
129
129
  r.push(MachineResponse::PushWFJob(
130
130
  self.create_cancelation_resolve(None).into(),
131
- ))
131
+ ));
132
132
  }
133
133
  r
134
134
  }
@@ -305,6 +305,20 @@ impl TryFrom<CommandType> for ActivityMachineEvents {
305
305
 
306
306
  impl Cancellable for ActivityMachine {
307
307
  fn cancel(&mut self) -> Result<Vec<MachineResponse>, MachineError<Self::Error>> {
308
+ if matches!(
309
+ self.state(),
310
+ ActivityMachineState::Completed(_)
311
+ | ActivityMachineState::Canceled(_)
312
+ | ActivityMachineState::Failed(_)
313
+ | ActivityMachineState::TimedOut(_)
314
+ ) {
315
+ // Ignore attempted cancels in terminal states
316
+ debug!(
317
+ "Attempted to cancel already resolved activity (seq {})",
318
+ self.shared_state.attrs.seq
319
+ );
320
+ return Ok(vec![]);
321
+ }
308
322
  let event = match self.shared_state.cancellation_type {
309
323
  ActivityCancellationType::Abandon => ActivityMachineEvents::Abandon,
310
324
  _ => ActivityMachineEvents::Cancel,
@@ -316,9 +330,15 @@ impl Cancellable for ActivityMachine {
316
330
  ActivityMachineCommand::RequestCancellation(cmd) => {
317
331
  self.machine_responses_from_cancel_request(cmd)
318
332
  }
319
- ActivityMachineCommand::Cancel(_details) => {
320
- // TODO: Convert payloads
321
- vec![self.create_cancelation_resolve(None).into()]
333
+ ActivityMachineCommand::Cancel(details) => {
334
+ vec![self
335
+ .create_cancelation_resolve(
336
+ details
337
+ .map(TryInto::try_into)
338
+ .transpose()
339
+ .unwrap_or_default(),
340
+ )
341
+ .into()]
322
342
  }
323
343
  x => panic!("Invalid cancel event response {:?}", x),
324
344
  })
@@ -665,7 +685,7 @@ fn notify_lang_activity_cancelled(
665
685
  ) -> ActivityMachineTransition<Canceled> {
666
686
  ActivityMachineTransition::ok_shared(
667
687
  vec![ActivityMachineCommand::Cancel(
668
- canceled_event.map(|e| e.details).flatten(),
688
+ canceled_event.and_then(|e| e.details),
669
689
  )],
670
690
  Canceled::default(),
671
691
  dat,
@@ -735,6 +755,7 @@ mod test {
735
755
  workflow::managed_wf::ManagedWFFunc,
736
756
  };
737
757
  use rstest::{fixture, rstest};
758
+ use std::mem::discriminant;
738
759
  use temporal_sdk_core_protos::coresdk::workflow_activation::{
739
760
  wf_activation_job, WfActivationJob,
740
761
  };
@@ -835,4 +856,22 @@ mod test {
835
856
  );
836
857
  wfm.shutdown().await.unwrap();
837
858
  }
859
+
860
+ #[test]
861
+ fn cancels_ignored_terminal() {
862
+ for state in [
863
+ ActivityMachineState::Canceled(Canceled {}),
864
+ Failed {}.into(),
865
+ TimedOut {}.into(),
866
+ Completed {}.into(),
867
+ ] {
868
+ let mut s = ActivityMachine {
869
+ state: state.clone(),
870
+ shared_state: Default::default(),
871
+ };
872
+ let cmds = s.cancel().unwrap();
873
+ assert_eq!(cmds.len(), 0);
874
+ assert_eq!(discriminant(&state), discriminant(&s.state));
875
+ }
876
+ }
838
877
  }
@@ -54,6 +54,12 @@ fsm! {
54
54
  Started --(ChildWorkflowExecutionTimedOut(i32), shared on_child_workflow_execution_timed_out) --> TimedOut;
55
55
  Started --(ChildWorkflowExecutionCancelled, shared on_child_workflow_execution_cancelled) --> Cancelled;
56
56
  Started --(ChildWorkflowExecutionTerminated, shared on_child_workflow_execution_terminated) --> Terminated;
57
+
58
+ // Ignore any spurious cancellations after resolution
59
+ Cancelled --(Cancel) --> Cancelled;
60
+ Failed --(Cancel) --> Failed;
61
+ TimedOut --(Cancel) --> TimedOut;
62
+ Completed --(Cancel) --> Completed;
57
63
  }
58
64
 
59
65
  pub struct ChildWorkflowExecutionStartedEvent {
@@ -288,7 +294,7 @@ pub(super) struct Terminated {}
288
294
  #[derive(Default, Clone)]
289
295
  pub(super) struct TimedOut {}
290
296
 
291
- #[derive(Default, Clone)]
297
+ #[derive(Default, Clone, Debug)]
292
298
  pub(super) struct SharedState {
293
299
  initiated_event_id: i64,
294
300
  started_event_id: i64,
@@ -630,6 +636,7 @@ mod test {
630
636
  };
631
637
  use anyhow::anyhow;
632
638
  use rstest::{fixture, rstest};
639
+ use std::mem::discriminant;
633
640
  use temporal_sdk_core_protos::coresdk::{
634
641
  child_workflow::child_workflow_result,
635
642
  workflow_activation::resolve_child_workflow_execution_start::Status as StartStatus,
@@ -643,11 +650,11 @@ mod test {
643
650
  }
644
651
 
645
652
  impl Expectation {
646
- fn try_from_u8(x: u8) -> Option<Self> {
653
+ const fn try_from_u8(x: u8) -> Option<Self> {
647
654
  Some(match x {
648
- 0 => Expectation::Success,
649
- 1 => Expectation::Failure,
650
- 2 => Expectation::StartFailure,
655
+ 0 => Self::Success,
656
+ 1 => Self::Failure,
657
+ 2 => Self::StartFailure,
651
658
  _ => return None,
652
659
  })
653
660
  }
@@ -693,12 +700,7 @@ mod test {
693
700
  };
694
701
  match (
695
702
  expectation,
696
- start_res
697
- .as_started()
698
- .unwrap()
699
- .result(&mut ctx)
700
- .await
701
- .status,
703
+ start_res.into_started().unwrap().result().await.status,
702
704
  ) {
703
705
  (Expectation::Success, Some(child_workflow_result::Status::Completed(_))) => {
704
706
  Ok(().into())
@@ -803,4 +805,22 @@ mod test {
803
805
  );
804
806
  wfm.shutdown().await.unwrap();
805
807
  }
808
+
809
+ #[test]
810
+ fn cancels_ignored_terminal() {
811
+ for state in [
812
+ ChildWorkflowMachineState::Cancelled(Cancelled {}),
813
+ Failed {}.into(),
814
+ TimedOut {}.into(),
815
+ Completed {}.into(),
816
+ ] {
817
+ let mut s = ChildWorkflowMachine {
818
+ state: state.clone(),
819
+ shared_state: Default::default(),
820
+ };
821
+ let cmds = s.cancel().unwrap();
822
+ assert_eq!(cmds.len(), 0);
823
+ assert_eq!(discriminant(&state), discriminant(&s.state));
824
+ }
825
+ }
806
826
  }
@@ -117,7 +117,7 @@ pub(super) struct CompleteWorkflowCommandRecorded {}
117
117
 
118
118
  impl From<CompleteWorkflowCommandCreated> for CompleteWorkflowCommandRecorded {
119
119
  fn from(_: CompleteWorkflowCommandCreated) -> Self {
120
- Default::default()
120
+ Self::default()
121
121
  }
122
122
  }
123
123
 
@@ -64,7 +64,7 @@ impl Created {
64
64
 
65
65
  impl From<ContinueAsNewWorkflowCommandCreated> for ContinueAsNewWorkflowCommandRecorded {
66
66
  fn from(_: ContinueAsNewWorkflowCommandCreated) -> Self {
67
- Default::default()
67
+ Self::default()
68
68
  }
69
69
  }
70
70
 
@@ -77,38 +77,34 @@ impl TryFrom<WorkflowCommand> for WFCommand {
77
77
 
78
78
  fn try_from(c: WorkflowCommand) -> Result<Self, Self::Error> {
79
79
  match c.variant.ok_or(EmptyWorkflowCommandErr)? {
80
- workflow_command::Variant::StartTimer(s) => Ok(WFCommand::AddTimer(s)),
81
- workflow_command::Variant::CancelTimer(s) => Ok(WFCommand::CancelTimer(s)),
82
- workflow_command::Variant::ScheduleActivity(s) => Ok(WFCommand::AddActivity(s)),
80
+ workflow_command::Variant::StartTimer(s) => Ok(Self::AddTimer(s)),
81
+ workflow_command::Variant::CancelTimer(s) => Ok(Self::CancelTimer(s)),
82
+ workflow_command::Variant::ScheduleActivity(s) => Ok(Self::AddActivity(s)),
83
83
  workflow_command::Variant::RequestCancelActivity(s) => {
84
- Ok(WFCommand::RequestCancelActivity(s))
84
+ Ok(Self::RequestCancelActivity(s))
85
85
  }
86
86
  workflow_command::Variant::CompleteWorkflowExecution(c) => {
87
- Ok(WFCommand::CompleteWorkflow(c))
87
+ Ok(Self::CompleteWorkflow(c))
88
88
  }
89
- workflow_command::Variant::FailWorkflowExecution(s) => Ok(WFCommand::FailWorkflow(s)),
90
- workflow_command::Variant::RespondToQuery(s) => Ok(WFCommand::QueryResponse(s)),
89
+ workflow_command::Variant::FailWorkflowExecution(s) => Ok(Self::FailWorkflow(s)),
90
+ workflow_command::Variant::RespondToQuery(s) => Ok(Self::QueryResponse(s)),
91
91
  workflow_command::Variant::ContinueAsNewWorkflowExecution(s) => {
92
- Ok(WFCommand::ContinueAsNew(s))
92
+ Ok(Self::ContinueAsNew(s))
93
93
  }
94
- workflow_command::Variant::CancelWorkflowExecution(s) => {
95
- Ok(WFCommand::CancelWorkflow(s))
96
- }
97
- workflow_command::Variant::SetPatchMarker(s) => Ok(WFCommand::SetPatchMarker(s)),
94
+ workflow_command::Variant::CancelWorkflowExecution(s) => Ok(Self::CancelWorkflow(s)),
95
+ workflow_command::Variant::SetPatchMarker(s) => Ok(Self::SetPatchMarker(s)),
98
96
  workflow_command::Variant::StartChildWorkflowExecution(s) => {
99
- Ok(WFCommand::AddChildWorkflow(s))
97
+ Ok(Self::AddChildWorkflow(s))
100
98
  }
101
99
  workflow_command::Variant::RequestCancelExternalWorkflowExecution(s) => {
102
- Ok(WFCommand::RequestCancelExternalWorkflow(s))
100
+ Ok(Self::RequestCancelExternalWorkflow(s))
103
101
  }
104
102
  workflow_command::Variant::SignalExternalWorkflowExecution(s) => {
105
- Ok(WFCommand::SignalExternalWorkflow(s))
106
- }
107
- workflow_command::Variant::CancelSignalWorkflow(s) => {
108
- Ok(WFCommand::CancelSignalWorkflow(s))
103
+ Ok(Self::SignalExternalWorkflow(s))
109
104
  }
105
+ workflow_command::Variant::CancelSignalWorkflow(s) => Ok(Self::CancelSignalWorkflow(s)),
110
106
  workflow_command::Variant::CancelUnstartedChildWorkflowExecution(s) => {
111
- Ok(WFCommand::CancelUnstartedChild(s))
107
+ Ok(Self::CancelUnstartedChild(s))
112
108
  }
113
109
  }
114
110
  }
@@ -170,9 +166,7 @@ where
170
166
  + Clone
171
167
  + Send
172
168
  + 'static,
173
- <SM as StateMachine>::Event: TryFrom<HistoryEvent>,
174
- <SM as StateMachine>::Event: TryFrom<CommandType>,
175
- <SM as StateMachine>::Event: Display,
169
+ <SM as StateMachine>::Event: TryFrom<HistoryEvent> + TryFrom<CommandType> + Display,
176
170
  WFMachinesError: From<<<SM as StateMachine>::Event as TryFrom<HistoryEvent>>::Error>,
177
171
  <SM as StateMachine>::Command: Debug + Display,
178
172
  <SM as StateMachine>::State: Display,
@@ -248,7 +242,8 @@ where
248
242
  let res = self.cancel();
249
243
  res.map_err(|e| match e {
250
244
  MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
251
- "Invalid transition while attempting to cancel in {}",
245
+ "Invalid transition while attempting to cancel {} in {}",
246
+ self.name(),
252
247
  self.state(),
253
248
  )),
254
249
  MachineError::Underlying(e) => e.into(),
@@ -107,7 +107,7 @@ impl PatchMachine {
107
107
  .into(),
108
108
  ),
109
109
  };
110
- let mut machine = PatchMachine {
110
+ let mut machine = Self {
111
111
  state: initial_state,
112
112
  shared_state: state,
113
113
  };
@@ -210,7 +210,7 @@ impl TryFrom<HistoryEvent> for PatchMachineEvents {
210
210
 
211
211
  fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
212
212
  match e.get_changed_marker_details() {
213
- Some((id, _)) => Ok(PatchMachineEvents::MarkerRecorded(id)),
213
+ Some((id, _)) => Ok(Self::MarkerRecorded(id)),
214
214
  _ => Err(WFMachinesError::Nondeterminism(format!(
215
215
  "Change machine cannot handle this event: {}",
216
216
  e
@@ -422,7 +422,9 @@ mod tests {
422
422
  commands[0].command_type,
423
423
  CommandType::ScheduleActivityTask as i32
424
424
  );
425
- let act = if !replaying {
425
+ let act = if replaying {
426
+ wfm.get_next_activation().await
427
+ } else {
426
428
  // Feed more history
427
429
  wfm.new_history(
428
430
  patch_marker_single_activity(marker_type)
@@ -431,8 +433,6 @@ mod tests {
431
433
  .into(),
432
434
  )
433
435
  .await
434
- } else {
435
- wfm.get_next_activation().await
436
436
  };
437
437
 
438
438
  if marker_type == MarkerType::Deprecated {
@@ -514,7 +514,9 @@ mod tests {
514
514
  if activity_id == expected_activity_id
515
515
  );
516
516
 
517
- let act = if !replaying {
517
+ let act = if replaying {
518
+ wfm.get_next_activation().await
519
+ } else {
518
520
  // Feed more history. Since we are *not* replaying, we *always* "have" the change
519
521
  // and the history should have the has-change timer. v3 of course always has the change
520
522
  // regardless.
@@ -525,8 +527,6 @@ mod tests {
525
527
  .into(),
526
528
  )
527
529
  .await
528
- } else {
529
- wfm.get_next_activation().await
530
530
  };
531
531
 
532
532
  let act = act.unwrap();
@@ -42,6 +42,10 @@ fsm! {
42
42
  SignalExternalCommandRecorded
43
43
  --(SignalExternalWorkflowExecutionFailed(SignalExternalWorkflowExecutionFailedCause),
44
44
  on_signal_external_workflow_execution_failed) --> Failed;
45
+
46
+ // Ignore any spurious cancellations after resolution
47
+ Cancelled --(Cancel) --> Cancelled;
48
+ Signaled --(Cancel) --> Signaled;
45
49
  }
46
50
 
47
51
  #[derive(Default, Clone)]
@@ -262,7 +266,7 @@ impl Cancellable for SignalExternalMachine {
262
266
  ..Default::default()
263
267
  }),
264
268
  }
265
- .into()]
269
+ .into()];
266
270
  }
267
271
  Some(_) => panic!("Signal external machine cancel produced unexpected result"),
268
272
  None => (),
@@ -285,6 +289,7 @@ mod tests {
285
289
  test_help::TestHistoryBuilder,
286
290
  workflow::managed_wf::ManagedWFFunc,
287
291
  };
292
+ use std::mem::discriminant;
288
293
  use temporal_sdk_core_protos::coresdk::workflow_activation::{
289
294
  wf_activation_job, WfActivationJob,
290
295
  };
@@ -382,4 +387,20 @@ mod tests {
382
387
  );
383
388
  wfm.shutdown().await.unwrap();
384
389
  }
390
+
391
+ #[test]
392
+ fn cancels_ignored_terminal() {
393
+ for state in [
394
+ SignalExternalMachineState::Cancelled(Cancelled {}),
395
+ Signaled {}.into(),
396
+ ] {
397
+ let mut s = SignalExternalMachine {
398
+ state: state.clone(),
399
+ shared_state: Default::default(),
400
+ };
401
+ let cmds = s.cancel().unwrap();
402
+ assert_eq!(cmds.len(), 0);
403
+ assert_eq!(discriminant(&state), discriminant(&s.state));
404
+ }
405
+ }
385
406
  }
@@ -39,6 +39,10 @@ fsm! {
39
39
  --(CommandCancelTimer, on_command_cancel_timer) --> CancelTimerCommandSent;
40
40
 
41
41
  CancelTimerCommandSent --(TimerCanceled) --> Canceled;
42
+
43
+ // Ignore any spurious cancellations after resolution
44
+ Canceled --(Cancel) --> Canceled;
45
+ Fired --(Cancel) --> Fired;
42
46
  }
43
47
 
44
48
  #[derive(Debug, derive_more::Display)]
@@ -195,13 +199,13 @@ impl StartCommandRecorded {
195
199
  dat: SharedState,
196
200
  attrs: TimerFiredEventAttributes,
197
201
  ) -> TimerMachineTransition<Fired> {
198
- if dat.attrs.seq.to_string() != attrs.timer_id {
202
+ if dat.attrs.seq.to_string() == attrs.timer_id {
203
+ TransitionResult::ok(vec![TimerMachineCommand::Complete], Fired::default())
204
+ } else {
199
205
  TransitionResult::Err(WFMachinesError::Fatal(format!(
200
206
  "Timer fired event did not have expected timer id {}, it was {}!",
201
207
  dat.attrs.seq, attrs.timer_id
202
208
  )))
203
- } else {
204
- TransitionResult::ok(vec![TimerMachineCommand::Complete], Fired::default())
205
209
  }
206
210
  }
207
211
 
@@ -275,6 +279,7 @@ mod test {
275
279
  workflow::managed_wf::ManagedWFFunc,
276
280
  };
277
281
  use rstest::{fixture, rstest};
282
+ use std::mem::discriminant;
278
283
  use std::time::Duration;
279
284
 
280
285
  #[fixture]
@@ -420,4 +425,17 @@ mod test {
420
425
  assert_eq!(commands.len(), 0);
421
426
  wfm.shutdown().await.unwrap();
422
427
  }
428
+
429
+ #[test]
430
+ fn cancels_ignored_terminal() {
431
+ for state in [TimerMachineState::Canceled(Canceled {}), Fired {}.into()] {
432
+ let mut s = TimerMachine {
433
+ state: state.clone(),
434
+ shared_state: Default::default(),
435
+ };
436
+ let cmds = s.cancel().unwrap();
437
+ assert_eq!(cmds.len(), 0);
438
+ assert_eq!(discriminant(&state), discriminant(&s.state));
439
+ }
440
+ }
423
441
  }
@@ -79,7 +79,7 @@ mod machine_coverage_report {
79
79
  workflow_task_state_machine::WorkflowTaskMachine,
80
80
  };
81
81
  use rustfsm::StateMachine;
82
- use std::{fs::File, io::Write, ops::Deref};
82
+ use std::{fs::File, io::Write};
83
83
 
84
84
  // This "test" needs to exist so that we have a way to join the spawned thread. Otherwise
85
85
  // it'll just get abandoned.
@@ -89,7 +89,7 @@ mod machine_coverage_report {
89
89
  #[ignore]
90
90
  fn reporter() {
91
91
  // Make sure thread handle exists
92
- let _ = COVERAGE_SENDER.deref();
92
+ let _ = &*COVERAGE_SENDER;
93
93
  // Join it
94
94
  THREAD_HANDLE
95
95
  .lock()
@@ -124,7 +124,7 @@ mod machine_coverage_report {
124
124
  m @ "WorkflowTaskMachine" => cover_transitions(m, &mut wf_task, coverage),
125
125
  m @ "FailWorkflowMachine" => cover_transitions(m, &mut fail_wf, coverage),
126
126
  m @ "ContinueAsNewWorkflowMachine" => {
127
- cover_transitions(m, &mut cont_as_new, coverage)
127
+ cover_transitions(m, &mut cont_as_new, coverage);
128
128
  }
129
129
  m @ "CancelWorkflowMachine" => cover_transitions(m, &mut cancel_wf, coverage),
130
130
  m @ "PatchMachine" => cover_transitions(m, &mut version, coverage),
@@ -150,7 +150,7 @@ where
150
150
  T: Into<wf_activation_job::Variant>,
151
151
  {
152
152
  fn from(v: T) -> Self {
153
- MachineResponse::PushWFJob(v.into())
153
+ Self::PushWFJob(v.into())
154
154
  }
155
155
  }
156
156
 
@@ -171,7 +171,7 @@ pub(crate) enum WFMachinesError {
171
171
 
172
172
  impl From<TimestampOutOfSystemRangeError> for WFMachinesError {
173
173
  fn from(_: TimestampOutOfSystemRangeError) -> Self {
174
- WFMachinesError::Fatal("Could not decode timestamp".to_string())
174
+ Self::Fatal("Could not decode timestamp".to_string())
175
175
  }
176
176
  }
177
177
 
@@ -210,7 +210,7 @@ impl WorkflowMachines {
210
210
  }
211
211
 
212
212
  /// Returns true if workflow has seen a terminal command
213
- pub(crate) fn workflow_is_finished(&self) -> bool {
213
+ pub(crate) const fn workflow_is_finished(&self) -> bool {
214
214
  self.workflow_end_time.is_some()
215
215
  }
216
216
 
@@ -486,7 +486,7 @@ impl WorkflowMachines {
486
486
  }
487
487
 
488
488
  fn set_current_time(&mut self, time: SystemTime) -> SystemTime {
489
- if self.current_wf_time.map(|t| t < time).unwrap_or(true) {
489
+ if self.current_wf_time.map_or(true, |t| t < time) {
490
490
  self.current_wf_time = Some(time);
491
491
  }
492
492
  self.current_wf_time
@@ -503,7 +503,7 @@ impl WorkflowMachines {
503
503
  let results = self.drive_me.fetch_workflow_iteration_output().await;
504
504
  let jobs = self.handle_driven_results(results)?;
505
505
  let has_new_lang_jobs = !jobs.is_empty();
506
- for job in jobs.into_iter() {
506
+ for job in jobs {
507
507
  self.drive_me.send_job(job);
508
508
  }
509
509
  self.prepare_commands()?;
@@ -626,15 +626,15 @@ impl WorkflowMachines {
626
626
  .machine_mut(c.machine)
627
627
  .handle_command(c.command.command_type())?;
628
628
  self.process_machine_responses(c.machine, machine_responses)?;
629
+ self.commands.push_back(c);
629
630
  }
630
- self.commands.push_back(c);
631
631
  }
632
632
  debug!(commands = %self.commands.display(), "prepared commands");
633
633
  Ok(())
634
634
  }
635
635
 
636
636
  /// After a machine handles either an event or a command, it produces [MachineResponses] which
637
- /// this function uses to drive sending jobs to lang, trigging new workflow tasks, etc.
637
+ /// this function uses to drive sending jobs to lang, triggering new workflow tasks, etc.
638
638
  fn process_machine_responses(
639
639
  &mut self,
640
640
  sm: MachineKey,
@@ -695,7 +695,7 @@ impl WorkflowMachines {
695
695
  self.current_wf_task_commands.push_back(timer);
696
696
  }
697
697
  WFCommand::CancelTimer(attrs) => {
698
- jobs.extend(self.process_cancellation(CommandID::Timer(attrs.seq))?)
698
+ jobs.extend(self.process_cancellation(CommandID::Timer(attrs.seq))?);
699
699
  }
700
700
  WFCommand::AddActivity(attrs) => {
701
701
  let seq = attrs.seq;
@@ -705,7 +705,7 @@ impl WorkflowMachines {
705
705
  self.current_wf_task_commands.push_back(activity);
706
706
  }
707
707
  WFCommand::RequestCancelActivity(attrs) => {
708
- jobs.extend(self.process_cancellation(CommandID::Activity(attrs.seq))?)
708
+ jobs.extend(self.process_cancellation(CommandID::Activity(attrs.seq))?);
709
709
  }
710
710
  WFCommand::CompleteWorkflow(attrs) => {
711
711
  self.metrics.wf_completed();
@@ -815,7 +815,7 @@ impl WorkflowMachines {
815
815
  self.current_wf_task_commands.push_back(sigm);
816
816
  }
817
817
  WFCommand::CancelSignalWorkflow(attrs) => {
818
- jobs.extend(self.process_cancellation(CommandID::SignalExternal(attrs.seq))?)
818
+ jobs.extend(self.process_cancellation(CommandID::SignalExternal(attrs.seq))?);
819
819
  }
820
820
  WFCommand::QueryResponse(_) => {
821
821
  // Nothing to do here, queries are handled above the machine level
@@ -840,7 +840,7 @@ impl WorkflowMachines {
840
840
  self.current_wf_task_commands.push_back(CommandAndMachine {
841
841
  command: c,
842
842
  machine: m_key,
843
- })
843
+ });
844
844
  }
845
845
  MachineResponse::PushWFJob(j) => {
846
846
  jobs.push(j);
@@ -68,15 +68,14 @@ impl PendingActivations {
68
68
  let mut inner = self.inner.write();
69
69
  let mut key_queue = inner.queue.iter().copied();
70
70
  let maybe_key = key_queue.position(|k| {
71
- if let Some(activation) = inner.activations.get(k) {
72
- predicate(&activation.run_id)
73
- } else {
74
- false
75
- }
71
+ inner
72
+ .activations
73
+ .get(k)
74
+ .map_or(false, |activation| predicate(&activation.run_id))
76
75
  });
77
76
 
78
77
  let maybe_key = maybe_key.map(|pos| inner.queue.remove(pos).unwrap());
79
- if let Some(key) = maybe_key {
78
+ maybe_key.and_then(|key| {
80
79
  if let Some(pa) = inner.activations.remove(key) {
81
80
  inner.by_run_id.remove(&pa.run_id);
82
81
  Some(pa)
@@ -87,9 +86,7 @@ impl PendingActivations {
87
86
  drop(inner); // Will deadlock when we recurse w/o this
88
87
  self.pop()
89
88
  }
90
- } else {
91
- None
92
- }
89
+ })
93
90
  }
94
91
 
95
92
  pub fn pop(&self) -> Option<WfActivation> {
@@ -119,17 +116,19 @@ fn merge_joblists(
119
116
  .as_mut_slice()
120
117
  .sort_by(evictions_always_last_compare);
121
118
  // Drop any duplicate evictions
122
- let truncate_len = if let Some(last_non_evict_job) = existing_list.iter().rev().position(|j| {
123
- !matches!(
124
- j.variant,
125
- Some(wf_activation_job::Variant::RemoveFromCache(_))
126
- )
127
- }) {
128
- existing_list.len() - last_non_evict_job + 1
129
- } else {
130
- 1
131
- };
132
- existing_list.truncate(truncate_len)
119
+ let truncate_len = existing_list
120
+ .iter()
121
+ .rev()
122
+ .position(|j| {
123
+ !matches!(
124
+ j.variant,
125
+ Some(wf_activation_job::Variant::RemoveFromCache(_))
126
+ )
127
+ })
128
+ .map_or(1, |last_non_evict_job| {
129
+ existing_list.len() - last_non_evict_job + 1
130
+ });
131
+ existing_list.truncate(truncate_len);
133
132
  }
134
133
 
135
134
  fn evictions_always_last_compare(a: &WfActivationJob, b: &WfActivationJob) -> Ordering {
@@ -167,8 +166,14 @@ mod tests {
167
166
  run_id: rid1.clone(),
168
167
  ..Default::default()
169
168
  });
170
- pas.push(create_evict_activation(rid1.clone()));
171
- pas.push(create_evict_activation(rid2.clone()));
169
+ pas.push(create_evict_activation(
170
+ rid1.clone(),
171
+ "whatever".to_string(),
172
+ ));
173
+ pas.push(create_evict_activation(
174
+ rid2.clone(),
175
+ "whatever".to_string(),
176
+ ));
172
177
  pas.push(WfActivation {
173
178
  run_id: rid2.clone(),
174
179
  ..Default::default()