@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
@@ -27,7 +27,7 @@ use crate::{
27
27
  },
28
28
  };
29
29
  use siphasher::sip::SipHasher13;
30
- use slotmap::SlotMap;
30
+ use slotmap::{SlotMap, SparseSecondaryMap};
31
31
  use std::{
32
32
  borrow::{Borrow, BorrowMut},
33
33
  collections::{HashMap, VecDeque},
@@ -39,13 +39,14 @@ use temporal_sdk_core_protos::{
39
39
  coresdk::{
40
40
  common::NamespacedWorkflowExecution,
41
41
  workflow_activation::{
42
- workflow_activation_job::{self, Variant},
43
- NotifyHasPatch, UpdateRandomSeed, WorkflowActivation,
42
+ workflow_activation_job, NotifyHasPatch, UpdateRandomSeed, WorkflowActivation,
43
+ },
44
+ workflow_commands::{
45
+ request_cancel_external_workflow_execution as cancel_we, ContinueAsNewWorkflowExecution,
44
46
  },
45
- workflow_commands::request_cancel_external_workflow_execution as cancel_we,
46
47
  },
47
48
  temporal::api::{
48
- command::v1::Command as ProtoCommand,
49
+ command::v1::{command::Attributes as ProtoCmdAttrs, Command as ProtoCommand},
49
50
  enums::v1::EventType,
50
51
  history::v1::{history_event, HistoryEvent},
51
52
  },
@@ -94,6 +95,9 @@ pub(crate) struct WorkflowMachines {
94
95
  current_wf_time: Option<SystemTime>,
95
96
 
96
97
  all_machines: SlotMap<MachineKey, Machines>,
98
+ /// If a machine key is in this map, that machine was created internally by core, not as a
99
+ /// command from lang.
100
+ machine_is_core_created: SparseSecondaryMap<MachineKey, ()>,
97
101
 
98
102
  /// A mapping for accessing machines associated to a particular event, where the key is the id
99
103
  /// of the initiating event for that machine.
@@ -153,7 +157,14 @@ pub enum MachineResponse {
153
157
  #[display(fmt = "PushWFJob({})", "_0")]
154
158
  PushWFJob(workflow_activation_job::Variant),
155
159
 
160
+ /// Pushes a new command into the list that will be sent to server once we respond with the
161
+ /// workflow task completion
156
162
  IssueNewCommand(ProtoCommand),
163
+ /// The machine requests the creation of another *different* machine. This acts as if lang
164
+ /// had replied to the activation with a command, but we use a special set of IDs to avoid
165
+ /// collisions.
166
+ #[display(fmt = "NewCoreOriginatedCommand({:?})", "_0")]
167
+ NewCoreOriginatedCommand(ProtoCmdAttrs),
157
168
  #[display(fmt = "IssueFakeLocalActivityMarker({})", "_0")]
158
169
  IssueFakeLocalActivityMarker(u32),
159
170
  #[display(fmt = "TriggerWFTaskStarted")]
@@ -162,9 +173,7 @@ pub enum MachineResponse {
162
173
  time: SystemTime,
163
174
  },
164
175
  #[display(fmt = "UpdateRunIdOnWorkflowReset({})", run_id)]
165
- UpdateRunIdOnWorkflowReset {
166
- run_id: String,
167
- },
176
+ UpdateRunIdOnWorkflowReset { run_id: String },
168
177
 
169
178
  /// Queue a local activity to be processed by the worker
170
179
  #[display(fmt = "QueueLocalActivity")]
@@ -220,6 +229,7 @@ impl WorkflowMachines {
220
229
  wft_start_time: None,
221
230
  current_wf_time: None,
222
231
  all_machines: Default::default(),
232
+ machine_is_core_created: Default::default(),
223
233
  machines_by_event_id: Default::default(),
224
234
  id_to_machine: Default::default(),
225
235
  commands: Default::default(),
@@ -315,6 +325,12 @@ impl WorkflowMachines {
315
325
  /// invalid state.
316
326
  #[instrument(level = "debug", skip(self, event), fields(event=%event))]
317
327
  fn handle_event(&mut self, event: HistoryEvent, has_next_event: bool) -> Result<()> {
328
+ if event.event_type() == EventType::Unspecified {
329
+ return Err(WFMachinesError::Fatal(format!(
330
+ "Event type is unspecified! This history is invalid. Event detail: {:?}",
331
+ event
332
+ )));
333
+ }
318
334
  if event.is_final_wf_execution_event() {
319
335
  self.have_seen_terminal_event = true;
320
336
  }
@@ -599,10 +615,7 @@ impl WorkflowMachines {
599
615
  /// the workflow code, handling them, and preparing them to be sent off to the server.
600
616
  pub(crate) async fn iterate_machines(&mut self) -> Result<()> {
601
617
  let results = self.drive_me.fetch_workflow_iteration_output().await;
602
- let jobs = self.handle_driven_results(results)?;
603
- for job in jobs {
604
- self.drive_me.send_job(job);
605
- }
618
+ self.handle_driven_results(results)?;
606
619
  self.prepare_commands()?;
607
620
  if self.workflow_is_finished() {
608
621
  if let Some(rt) = self.total_runtime() {
@@ -755,10 +768,21 @@ impl WorkflowMachines {
755
768
  debug!(responses = %machine_responses.display(), machine_name = %sm.kind(),
756
769
  "Machine produced responses");
757
770
  }
771
+ self.process_machine_resps_impl(smk, machine_responses)
772
+ }
773
+
774
+ fn process_machine_resps_impl(
775
+ &mut self,
776
+ smk: MachineKey,
777
+ machine_responses: Vec<MachineResponse>,
778
+ ) -> Result<()> {
758
779
  for response in machine_responses {
759
780
  match response {
760
781
  MachineResponse::PushWFJob(a) => {
761
- self.drive_me.send_job(a);
782
+ // We don't need to notify lang about jobs created by core-internal machines
783
+ if !self.machine_is_core_created.contains_key(smk) {
784
+ self.drive_me.send_job(a);
785
+ }
762
786
  }
763
787
  MachineResponse::TriggerWFTaskStarted {
764
788
  task_started_event_id,
@@ -782,6 +806,27 @@ impl WorkflowMachines {
782
806
  machine: smk,
783
807
  })
784
808
  }
809
+ MachineResponse::NewCoreOriginatedCommand(attrs) => match attrs {
810
+ ProtoCmdAttrs::RequestCancelExternalWorkflowExecutionCommandAttributes(
811
+ attrs,
812
+ ) => {
813
+ let we = NamespacedWorkflowExecution {
814
+ namespace: attrs.namespace,
815
+ workflow_id: attrs.workflow_id,
816
+ run_id: attrs.run_id,
817
+ };
818
+ self.add_cmd_to_wf_task(
819
+ new_external_cancel(0, we, attrs.child_workflow_only, attrs.reason),
820
+ CommandIdKind::CoreInternal,
821
+ );
822
+ }
823
+ c => {
824
+ return Err(WFMachinesError::Fatal(format!(
825
+ "A machine requested to create a new command of an unsupported type: {:?}",
826
+ c
827
+ )))
828
+ }
829
+ },
785
830
  MachineResponse::IssueFakeLocalActivityMarker(seq) => {
786
831
  self.current_wf_task_commands.push_back(CommandAndMachine {
787
832
  command: MachineAssociatedCommand::FakeLocalActivityMarker(seq),
@@ -791,11 +836,44 @@ impl WorkflowMachines {
791
836
  MachineResponse::QueueLocalActivity(act) => {
792
837
  self.local_activity_data.enqueue(act);
793
838
  }
794
- MachineResponse::RequestCancelLocalActivity(_) => {
795
- panic!(
796
- "Request cancel local activity should not be returned from \
797
- anything other than explicit cancellation"
798
- )
839
+ MachineResponse::RequestCancelLocalActivity(seq) => {
840
+ // We might already know about the status from a pre-resolution. Apply it if so.
841
+ // We need to do this because otherwise we might need to perform additional
842
+ // activations during replay that didn't happen during execution, just like
843
+ // we sometimes pre-resolve activities when first requested.
844
+ if let Some(preres) = self.local_activity_data.take_preresolution(seq) {
845
+ if let Machines::LocalActivityMachine(lam) = self.machine_mut(smk) {
846
+ let more_responses = lam.try_resolve_with_dat(preres)?;
847
+ self.process_machine_responses(smk, more_responses)?;
848
+ } else {
849
+ panic!("A non local-activity machine returned a request cancel LA response");
850
+ }
851
+ }
852
+ // If it's in the request queue, just rip it out.
853
+ else if let Some(removed_act) =
854
+ self.local_activity_data.remove_from_queue(seq)
855
+ {
856
+ // We removed it. Notify the machine that the activity cancelled.
857
+ if let Machines::LocalActivityMachine(lam) = self.machine_mut(smk) {
858
+ let more_responses = lam.try_resolve(
859
+ LocalActivityExecutionResult::empty_cancel(),
860
+ Duration::from_secs(0),
861
+ removed_act.attempt,
862
+ None,
863
+ None,
864
+ )?;
865
+ self.process_machine_responses(smk, more_responses)?;
866
+ } else {
867
+ panic!("A non local-activity machine returned a request cancel LA response");
868
+ }
869
+ } else {
870
+ // Finally, if we know about the LA at all, it's currently running, so
871
+ // queue the cancel request to be given to the LA manager.
872
+ self.local_activity_data.enqueue_cancel(ExecutingLAId {
873
+ run_id: self.run_id.clone(),
874
+ seq_num: seq,
875
+ });
876
+ }
799
877
  }
800
878
  MachineResponse::AbandonLocalActivity(seq) => {
801
879
  self.local_activity_data.done_executing(seq);
@@ -816,26 +894,25 @@ impl WorkflowMachines {
816
894
  /// as part of command processing. For example some types of activity cancellation need to
817
895
  /// immediately unblock lang side without having it to poll for an actual workflow task from the
818
896
  /// server.
819
- fn handle_driven_results(
820
- &mut self,
821
- results: Vec<WFCommand>,
822
- ) -> Result<Vec<workflow_activation_job::Variant>> {
823
- let mut jobs = vec![];
897
+ fn handle_driven_results(&mut self, results: Vec<WFCommand>) -> Result<()> {
824
898
  for cmd in results {
825
899
  match cmd {
826
900
  WFCommand::AddTimer(attrs) => {
827
901
  let seq = attrs.seq;
828
- self.add_cmd_to_wf_task(new_timer(attrs), Some(CommandID::Timer(seq)));
902
+ self.add_cmd_to_wf_task(new_timer(attrs), CommandID::Timer(seq).into());
829
903
  }
830
904
  WFCommand::UpsertSearchAttributes(attrs) => {
831
- self.add_cmd_to_wf_task(upsert_search_attrs(attrs), None);
905
+ self.add_cmd_to_wf_task(
906
+ upsert_search_attrs(attrs),
907
+ CommandIdKind::NeverResolves,
908
+ );
832
909
  }
833
910
  WFCommand::CancelTimer(attrs) => {
834
- jobs.extend(self.process_cancellation(CommandID::Timer(attrs.seq))?);
911
+ self.process_cancellation(CommandID::Timer(attrs.seq))?;
835
912
  }
836
913
  WFCommand::AddActivity(attrs) => {
837
914
  let seq = attrs.seq;
838
- self.add_cmd_to_wf_task(new_activity(attrs), Some(CommandID::Activity(seq)));
915
+ self.add_cmd_to_wf_task(new_activity(attrs), CommandID::Activity(seq).into());
839
916
  }
840
917
  WFCommand::AddLocalActivity(attrs) => {
841
918
  let seq = attrs.seq;
@@ -863,10 +940,10 @@ impl WorkflowMachines {
863
940
  self.process_machine_responses(machkey, mach_resp)?;
864
941
  }
865
942
  WFCommand::RequestCancelActivity(attrs) => {
866
- jobs.extend(self.process_cancellation(CommandID::Activity(attrs.seq))?);
943
+ self.process_cancellation(CommandID::Activity(attrs.seq))?;
867
944
  }
868
945
  WFCommand::RequestCancelLocalActivity(attrs) => {
869
- jobs.extend(self.process_cancellation(CommandID::LocalActivity(attrs.seq))?);
946
+ self.process_cancellation(CommandID::LocalActivity(attrs.seq))?;
870
947
  }
871
948
  WFCommand::CompleteWorkflow(attrs) => {
872
949
  self.metrics.wf_completed();
@@ -878,6 +955,7 @@ impl WorkflowMachines {
878
955
  }
879
956
  WFCommand::ContinueAsNew(attrs) => {
880
957
  self.metrics.wf_continued_as_new();
958
+ let attrs = self.augment_continue_as_new_with_current_values(attrs);
881
959
  self.add_terminal_command(continue_as_new(attrs));
882
960
  }
883
961
  WFCommand::CancelWorkflow(attrs) => {
@@ -892,7 +970,7 @@ impl WorkflowMachines {
892
970
  {
893
971
  self.add_cmd_to_wf_task(
894
972
  has_change(attrs.patch_id.clone(), self.replaying, attrs.deprecated),
895
- None,
973
+ CommandIdKind::NeverResolves,
896
974
  );
897
975
 
898
976
  if let Some(ci) = self.encountered_change_markers.get_mut(&attrs.patch_id) {
@@ -911,12 +989,12 @@ impl WorkflowMachines {
911
989
  let seq = attrs.seq;
912
990
  self.add_cmd_to_wf_task(
913
991
  new_child_workflow(attrs),
914
- Some(CommandID::ChildWorkflowStart(seq)),
992
+ CommandID::ChildWorkflowStart(seq).into(),
915
993
  );
916
994
  }
917
- WFCommand::CancelUnstartedChild(attrs) => jobs.extend(self.process_cancellation(
995
+ WFCommand::CancelChild(attrs) => self.process_cancellation(
918
996
  CommandID::ChildWorkflowStart(attrs.child_workflow_seq),
919
- )?),
997
+ )?,
920
998
  WFCommand::RequestCancelExternalWorkflow(attrs) => {
921
999
  let (we, only_child) = match attrs.target {
922
1000
  None => {
@@ -942,18 +1020,18 @@ impl WorkflowMachines {
942
1020
  only_child,
943
1021
  format!("Cancel requested by workflow with run id {}", self.run_id),
944
1022
  ),
945
- Some(CommandID::CancelExternal(attrs.seq)),
1023
+ CommandID::CancelExternal(attrs.seq).into(),
946
1024
  );
947
1025
  }
948
1026
  WFCommand::SignalExternalWorkflow(attrs) => {
949
1027
  let seq = attrs.seq;
950
1028
  self.add_cmd_to_wf_task(
951
1029
  new_external_signal(attrs, &self.namespace)?,
952
- Some(CommandID::SignalExternal(seq)),
1030
+ CommandID::SignalExternal(seq).into(),
953
1031
  );
954
1032
  }
955
1033
  WFCommand::CancelSignalWorkflow(attrs) => {
956
- jobs.extend(self.process_cancellation(CommandID::SignalExternal(attrs.seq))?);
1034
+ self.process_cancellation(CommandID::SignalExternal(attrs.seq))?;
957
1035
  }
958
1036
  WFCommand::QueryResponse(_) => {
959
1037
  // Nothing to do here, queries are handled above the machine level
@@ -962,80 +1040,18 @@ impl WorkflowMachines {
962
1040
  WFCommand::NoCommandsFromLang => (),
963
1041
  }
964
1042
  }
965
- Ok(jobs)
1043
+ Ok(())
966
1044
  }
967
1045
 
968
1046
  /// Given a command id to attempt to cancel, try to cancel it and return any jobs that should
969
1047
  /// be included in the activation
970
- fn process_cancellation(&mut self, id: CommandID) -> Result<Vec<Variant>> {
971
- let mut jobs = vec![];
1048
+ fn process_cancellation(&mut self, id: CommandID) -> Result<()> {
972
1049
  let m_key = self.get_machine_key(id)?;
973
- let machine_resps = self.machine_mut(m_key).cancel()?;
1050
+ let mach = self.machine_mut(m_key);
1051
+ let machine_resps = mach.cancel()?;
974
1052
  debug!(machine_responses = %machine_resps.display(), cmd_id = ?id,
975
1053
  "Cancel request responses");
976
- for r in machine_resps {
977
- match r {
978
- MachineResponse::IssueNewCommand(c) => {
979
- self.current_wf_task_commands.push_back(CommandAndMachine {
980
- command: MachineAssociatedCommand::Real(Box::new(c)),
981
- machine: m_key,
982
- });
983
- }
984
- MachineResponse::PushWFJob(j) => {
985
- jobs.push(j);
986
- }
987
- MachineResponse::RequestCancelLocalActivity(seq) => {
988
- // We might already know about the status from a pre-resolution. Apply it if so.
989
- // We need to do this because otherwise we might need to perform additional
990
- // activations during replay that didn't happen during execution, just like
991
- // we sometimes pre-resolve activities when first requested.
992
- if let Some(preres) = self.local_activity_data.take_preresolution(seq) {
993
- if let Machines::LocalActivityMachine(lam) = self.machine_mut(m_key) {
994
- let more_responses = lam.try_resolve_with_dat(preres)?;
995
- self.process_machine_responses(m_key, more_responses)?;
996
- } else {
997
- panic!("A non local-activity machine returned a request cancel LA response");
998
- }
999
- }
1000
- // If it's in the request queue, just rip it out.
1001
- else if let Some(removed_act) =
1002
- self.local_activity_data.remove_from_queue(seq)
1003
- {
1004
- // We removed it. Notify the machine that the activity cancelled.
1005
- if let Machines::LocalActivityMachine(lam) = self.machine_mut(m_key) {
1006
- let more_responses = lam.try_resolve(
1007
- LocalActivityExecutionResult::empty_cancel(),
1008
- Duration::from_secs(0),
1009
- removed_act.attempt,
1010
- None,
1011
- None,
1012
- )?;
1013
- self.process_machine_responses(m_key, more_responses)?;
1014
- } else {
1015
- panic!("A non local-activity machine returned a request cancel LA response");
1016
- }
1017
- } else {
1018
- // Finally, if we know about the LA at all, it's currently running, so
1019
- // queue the cancel request to be given to the LA manager.
1020
- self.local_activity_data.enqueue_cancel(ExecutingLAId {
1021
- run_id: self.run_id.clone(),
1022
- seq_num: seq,
1023
- });
1024
- }
1025
- }
1026
- MachineResponse::AbandonLocalActivity(seq) => {
1027
- self.local_activity_data.done_executing(seq);
1028
- }
1029
- MachineResponse::UpdateWFTime(None) => {}
1030
- v => {
1031
- return Err(WFMachinesError::Fatal(format!(
1032
- "Unexpected machine response {:?} when cancelling {:?}",
1033
- v, id
1034
- )));
1035
- }
1036
- }
1037
- }
1038
- Ok(jobs)
1054
+ self.process_machine_resps_impl(m_key, machine_resps)
1039
1055
  }
1040
1056
 
1041
1057
  fn get_machine_key(&self, id: CommandID) -> Result<MachineKey> {
@@ -1051,11 +1067,14 @@ impl WorkflowMachines {
1051
1067
  }
1052
1068
 
1053
1069
  /// Add a new command/machines for that command to the current workflow task
1054
- fn add_cmd_to_wf_task(&mut self, machine: NewMachineWithCommand, id: Option<CommandID>) {
1070
+ fn add_cmd_to_wf_task(&mut self, machine: NewMachineWithCommand, id: CommandIdKind) {
1055
1071
  let mach = self.add_new_command_machine(machine);
1056
- if let Some(id) = id {
1072
+ if let CommandIdKind::LangIssued(id) = id {
1057
1073
  self.id_to_machine.insert(id, mach.machine);
1058
1074
  }
1075
+ if matches!(id, CommandIdKind::CoreInternal) {
1076
+ self.machine_is_core_created.insert(mach.machine, ());
1077
+ }
1059
1078
  self.current_wf_task_commands.push_back(mach);
1060
1079
  }
1061
1080
 
@@ -1080,6 +1099,32 @@ impl WorkflowMachines {
1080
1099
  .expect("Machine must exist")
1081
1100
  .borrow_mut()
1082
1101
  }
1102
+
1103
+ fn augment_continue_as_new_with_current_values(
1104
+ &self,
1105
+ mut attrs: ContinueAsNewWorkflowExecution,
1106
+ ) -> ContinueAsNewWorkflowExecution {
1107
+ if let Some(started_info) = self.drive_me.get_started_info() {
1108
+ if attrs.memo.is_empty() {
1109
+ attrs.memo = started_info
1110
+ .memo
1111
+ .clone()
1112
+ .map(Into::into)
1113
+ .unwrap_or_default();
1114
+ }
1115
+ if attrs.search_attributes.is_empty() {
1116
+ attrs.search_attributes = started_info
1117
+ .search_attrs
1118
+ .clone()
1119
+ .map(Into::into)
1120
+ .unwrap_or_default();
1121
+ }
1122
+ if attrs.retry_policy.is_none() {
1123
+ attrs.retry_policy = started_info.retry_policy.clone();
1124
+ }
1125
+ }
1126
+ attrs
1127
+ }
1083
1128
  }
1084
1129
 
1085
1130
  fn str_to_randomness_seed(run_id: &str) -> u64 {
@@ -1127,3 +1172,13 @@ fn change_marker_handling(
1127
1172
  }
1128
1173
  Ok(ChangeMarkerOutcome::Normal)
1129
1174
  }
1175
+
1176
+ #[derive(derive_more::From)]
1177
+ enum CommandIdKind {
1178
+ /// A normal command, requested by lang
1179
+ LangIssued(CommandID),
1180
+ /// A command created internally
1181
+ CoreInternal,
1182
+ /// A command which is fire-and-forget (ex: Upsert search attribs)
1183
+ NeverResolves,
1184
+ }
@@ -499,7 +499,8 @@ enum RunActionOutcome {
499
499
  AfterHeartbeatTimeout(Option<ActivationOrAuto>),
500
500
  }
501
501
 
502
- #[derive(Debug)]
502
+ #[derive(derive_more::DebugCustom)]
503
+ #[debug(fmt = "RunUpdateErr({:?})", source)]
503
504
  struct RunUpdateErr {
504
505
  source: WFMachinesError,
505
506
  complete_resp_chan: Option<oneshot::Sender<ActivationCompleteResult>>,