temporalio 0.0.2 → 0.1.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -23
  3. data/bridge/Cargo.lock +168 -59
  4. data/bridge/Cargo.toml +4 -2
  5. data/bridge/sdk-core/README.md +19 -6
  6. data/bridge/sdk-core/client/src/lib.rs +215 -39
  7. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  8. data/bridge/sdk-core/client/src/raw.rs +4 -4
  9. data/bridge/sdk-core/client/src/retry.rs +32 -20
  10. data/bridge/sdk-core/core/Cargo.toml +22 -9
  11. data/bridge/sdk-core/core/src/abstractions.rs +203 -14
  12. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
  13. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  14. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
  15. data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
  16. data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
  17. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
  18. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  19. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  20. data/bridge/sdk-core/core/src/lib.rs +16 -9
  21. data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
  22. data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
  23. data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
  24. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
  25. data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
  26. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  27. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  28. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
  29. data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
  30. data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
  31. data/bridge/sdk-core/core/src/worker/client.rs +18 -2
  32. data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
  33. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  34. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  35. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
  36. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
  37. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
  38. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
  39. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
  40. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
  41. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
  54. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
  55. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
  56. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
  57. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  58. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  60. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
  63. data/bridge/sdk-core/core-api/Cargo.toml +2 -1
  64. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  65. data/bridge/sdk-core/core-api/src/lib.rs +6 -2
  66. data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
  67. data/bridge/sdk-core/core-api/src/worker.rs +14 -1
  68. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  69. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  70. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  71. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  72. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  73. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  74. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  75. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  76. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  77. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  78. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  79. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  80. data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  81. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  82. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  83. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  84. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  85. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  86. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  87. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  88. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  89. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  90. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  91. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
  92. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
  93. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  94. data/bridge/sdk-core/sdk/Cargo.toml +3 -2
  95. data/bridge/sdk-core/sdk/src/lib.rs +87 -20
  96. data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
  97. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  98. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
  99. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
  100. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
  101. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
  102. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  103. data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
  104. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  105. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  106. data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
  107. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  108. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  109. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  110. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  111. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  115. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  116. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  117. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  118. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  120. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  121. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  122. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  123. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
  124. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
  125. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  126. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  127. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  129. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  130. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  131. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  132. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
  133. data/bridge/sdk-core/tests/main.rs +3 -13
  134. data/bridge/sdk-core/tests/runner.rs +75 -36
  135. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  136. data/bridge/src/connection.rs +41 -25
  137. data/bridge/src/lib.rs +269 -14
  138. data/bridge/src/runtime.rs +1 -1
  139. data/bridge/src/test_server.rs +153 -0
  140. data/bridge/src/worker.rs +89 -16
  141. data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
  142. data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
  143. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
  144. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
  145. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
  146. data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
  147. data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
  148. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
  149. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
  150. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  151. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  152. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  153. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  154. data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
  155. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
  156. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  157. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  158. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  159. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  160. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  161. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  162. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
  163. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
  164. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  165. data/lib/temporalio/activity/context.rb +13 -8
  166. data/lib/temporalio/activity/info.rb +1 -1
  167. data/lib/temporalio/bridge/connect_options.rb +15 -0
  168. data/lib/temporalio/bridge/retry_config.rb +24 -0
  169. data/lib/temporalio/bridge/tls_options.rb +19 -0
  170. data/lib/temporalio/client/implementation.rb +8 -8
  171. data/lib/temporalio/connection/retry_config.rb +44 -0
  172. data/lib/temporalio/connection/service.rb +20 -0
  173. data/lib/temporalio/connection/test_service.rb +92 -0
  174. data/lib/temporalio/connection/tls_options.rb +51 -0
  175. data/lib/temporalio/connection/workflow_service.rb +731 -0
  176. data/lib/temporalio/connection.rb +55 -720
  177. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  178. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  179. data/lib/temporalio/interceptor/chain.rb +5 -5
  180. data/lib/temporalio/interceptor/client.rb +8 -4
  181. data/lib/temporalio/interceptor.rb +22 -0
  182. data/lib/temporalio/retry_policy.rb +13 -3
  183. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  184. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  185. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  186. data/lib/temporalio/testing.rb +175 -0
  187. data/lib/temporalio/version.rb +1 -1
  188. data/lib/temporalio/worker/activity_runner.rb +26 -4
  189. data/lib/temporalio/worker/activity_worker.rb +44 -18
  190. data/lib/temporalio/worker/sync_worker.rb +47 -11
  191. data/lib/temporalio/worker.rb +27 -21
  192. data/lib/temporalio/workflow/async.rb +46 -0
  193. data/lib/temporalio/workflow/future.rb +138 -0
  194. data/lib/temporalio/workflow/info.rb +76 -0
  195. data/temporalio.gemspec +4 -3
  196. metadata +67 -17
  197. data/bridge/sdk-core/Cargo.lock +0 -2606
  198. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
  199. data/lib/bridge.so +0 -0
  200. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
  201. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
  202. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
@@ -1,26 +1,27 @@
1
1
  use anyhow::anyhow;
2
2
  use futures::future::join_all;
3
- use futures_util::stream::{FuturesUnordered, StreamExt};
4
3
  use std::{
5
4
  sync::atomic::{AtomicU8, Ordering},
6
5
  time::Duration,
7
6
  };
8
- use temporal_client::{WorkflowClientTrait, WorkflowOptions};
7
+ use temporal_client::WorkflowOptions;
9
8
  use temporal_sdk::{
10
- interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, ActivityOptions,
11
- CancellableFuture, LocalActivityOptions, WfContext, WorkflowResult,
9
+ interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, CancellableFuture,
10
+ LocalActivityOptions, WfContext, WorkflowResult,
12
11
  };
13
12
  use temporal_sdk_core::replay::HistoryForReplay;
14
13
  use temporal_sdk_core_protos::{
15
14
  coresdk::{
16
- workflow_commands::ActivityCancellationType,
15
+ workflow_commands::workflow_command::Variant, workflow_commands::ActivityCancellationType,
16
+ workflow_completion, workflow_completion::workflow_activation_completion,
17
17
  workflow_completion::WorkflowActivationCompletion, AsJsonPayloadExt,
18
18
  },
19
19
  temporal::api::{common::v1::RetryPolicy, enums::v1::TimeoutType},
20
20
  TestHistoryBuilder,
21
21
  };
22
22
  use temporal_sdk_core_test_utils::{
23
- history_from_proto_binary, init_integ_telem, replay_sdk_worker, CoreWfStarter,
23
+ history_from_proto_binary, init_integ_telem, replay_sdk_worker, workflows::la_problem_workflow,
24
+ CoreWfStarter,
24
25
  };
25
26
  use tokio_util::sync::CancellationToken;
26
27
 
@@ -49,15 +50,7 @@ async fn one_local_activity() {
49
50
  worker.register_wf(wf_name.to_owned(), one_local_activity_wf);
50
51
  worker.register_activity("echo_activity", echo);
51
52
 
52
- worker
53
- .submit_wf(
54
- wf_name.to_owned(),
55
- wf_name.to_owned(),
56
- vec![],
57
- WorkflowOptions::default(),
58
- )
59
- .await
60
- .unwrap();
53
+ starter.start_with_worker(wf_name, &mut worker).await;
61
54
  worker.run_until_done().await.unwrap();
62
55
  }
63
56
 
@@ -80,15 +73,7 @@ async fn local_act_concurrent_with_timer() {
80
73
  worker.register_wf(wf_name.to_owned(), local_act_concurrent_with_timer_wf);
81
74
  worker.register_activity("echo_activity", echo);
82
75
 
83
- worker
84
- .submit_wf(
85
- wf_name.to_owned(),
86
- wf_name.to_owned(),
87
- vec![],
88
- WorkflowOptions::default(),
89
- )
90
- .await
91
- .unwrap();
76
+ starter.start_with_worker(wf_name, &mut worker).await;
92
77
  worker.run_until_done().await.unwrap();
93
78
  }
94
79
 
@@ -112,15 +97,7 @@ async fn local_act_then_timer_then_wait_result() {
112
97
  worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
113
98
  worker.register_activity("echo_activity", echo);
114
99
 
115
- worker
116
- .submit_wf(
117
- wf_name.to_owned(),
118
- wf_name.to_owned(),
119
- vec![],
120
- WorkflowOptions::default(),
121
- )
122
- .await
123
- .unwrap();
100
+ starter.start_with_worker(wf_name, &mut worker).await;
124
101
  worker.run_until_done().await.unwrap();
125
102
  }
126
103
 
@@ -128,7 +105,7 @@ async fn local_act_then_timer_then_wait_result() {
128
105
  async fn long_running_local_act_with_timer() {
129
106
  let wf_name = "long_running_local_act_with_timer";
130
107
  let mut starter = CoreWfStarter::new(wf_name);
131
- starter.wft_timeout(Duration::from_secs(1));
108
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
132
109
  let mut worker = starter.worker().await;
133
110
  worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
134
111
  worker.register_activity("echo_activity", |_ctx: ActContext, str: String| async {
@@ -136,15 +113,7 @@ async fn long_running_local_act_with_timer() {
136
113
  Ok(str)
137
114
  });
138
115
 
139
- worker
140
- .submit_wf(
141
- wf_name.to_owned(),
142
- wf_name.to_owned(),
143
- vec![],
144
- WorkflowOptions::default(),
145
- )
146
- .await
147
- .unwrap();
116
+ starter.start_with_worker(wf_name, &mut worker).await;
148
117
  worker.run_until_done().await.unwrap();
149
118
  }
150
119
 
@@ -153,7 +122,7 @@ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
153
122
  .map(|i| {
154
123
  ctx.local_activity(LocalActivityOptions {
155
124
  activity_type: "echo_activity".to_string(),
156
- input: format!("Hi {}", i)
125
+ input: format!("Hi {i}")
157
126
  .as_json_payload()
158
127
  .expect("serializes fine"),
159
128
  ..Default::default()
@@ -174,15 +143,7 @@ async fn local_act_fanout() {
174
143
  worker.register_wf(wf_name.to_owned(), local_act_fanout_wf);
175
144
  worker.register_activity("echo_activity", echo);
176
145
 
177
- worker
178
- .submit_wf(
179
- wf_name.to_owned(),
180
- wf_name.to_owned(),
181
- vec![],
182
- WorkflowOptions::default(),
183
- )
184
- .await
185
- .unwrap();
146
+ starter.start_with_worker(wf_name, &mut worker).await;
186
147
  worker.run_until_done().await.unwrap();
187
148
  }
188
149
 
@@ -237,7 +198,7 @@ async fn local_act_retry_timer_backoff() {
237
198
  #[case::abandon(ActivityCancellationType::Abandon)]
238
199
  #[tokio::test]
239
200
  async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
240
- let wf_name = format!("cancel_immediate_{:?}", cancel_type);
201
+ let wf_name = format!("cancel_immediate_{cancel_type:?}");
241
202
  let mut starter = CoreWfStarter::new(&wf_name);
242
203
  let mut worker = starter.worker().await;
243
204
  worker.register_wf(&wf_name, move |ctx: WfContext| async move {
@@ -271,17 +232,10 @@ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
271
232
  }
272
233
  });
273
234
 
274
- worker
275
- .submit_wf(
276
- wf_name.to_owned(),
277
- wf_name.to_owned(),
278
- vec![],
279
- WorkflowOptions::default(),
280
- )
281
- .await
282
- .unwrap();
235
+ starter.start_with_worker(wf_name, &mut worker).await;
283
236
  worker
284
237
  .run_until_done_intercepted(Some(LACancellerInterceptor {
238
+ cancel_on_workflow_completed: false,
285
239
  token: manual_cancel,
286
240
  }))
287
241
  .await
@@ -290,12 +244,29 @@ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
290
244
 
291
245
  struct LACancellerInterceptor {
292
246
  token: CancellationToken,
247
+ cancel_on_workflow_completed: bool,
293
248
  }
294
249
  #[async_trait::async_trait(?Send)]
295
250
  impl WorkerInterceptor for LACancellerInterceptor {
296
- async fn on_workflow_activation_completion(&self, _: &WorkflowActivationCompletion) {}
251
+ async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
252
+ if !self.cancel_on_workflow_completed {
253
+ return;
254
+ }
255
+ if let Some(workflow_activation_completion::Status::Successful(
256
+ workflow_completion::Success { commands, .. },
257
+ )) = completion.status.as_ref()
258
+ {
259
+ if let Some(&Variant::CompleteWorkflowExecution(_)) =
260
+ commands.last().and_then(|v| v.variant.as_ref())
261
+ {
262
+ self.token.cancel();
263
+ }
264
+ }
265
+ }
297
266
  fn on_shutdown(&self, _: &temporal_sdk::Worker) {
298
- self.token.cancel()
267
+ if !self.cancel_on_workflow_completed {
268
+ self.token.cancel()
269
+ }
299
270
  }
300
271
  }
301
272
 
@@ -313,12 +284,9 @@ async fn cancel_after_act_starts(
313
284
  )]
314
285
  cancel_type: ActivityCancellationType,
315
286
  ) {
316
- let wf_name = format!(
317
- "cancel_after_act_starts_timer_{:?}_{:?}",
318
- cancel_on_backoff, cancel_type
319
- );
287
+ let wf_name = format!("cancel_after_act_starts_{cancel_on_backoff:?}_{cancel_type:?}");
320
288
  let mut starter = CoreWfStarter::new(&wf_name);
321
- starter.wft_timeout(Duration::from_secs(1));
289
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
322
290
  let mut worker = starter.worker().await;
323
291
  let bo_dur = cancel_on_backoff.unwrap_or_else(|| Duration::from_secs(1));
324
292
  worker.register_wf(&wf_name, move |ctx: WfContext| async move {
@@ -378,21 +346,17 @@ async fn cancel_after_act_starts(
378
346
  }
379
347
  });
380
348
 
381
- worker
382
- .submit_wf(
383
- wf_name.to_owned(),
384
- wf_name.to_owned(),
385
- vec![],
386
- WorkflowOptions::default(),
387
- )
388
- .await
389
- .unwrap();
349
+ starter.start_with_worker(&wf_name, &mut worker).await;
390
350
  worker
391
351
  .run_until_done_intercepted(Some(LACancellerInterceptor {
392
352
  token: manual_cancel,
353
+ // Only needed for this one case since the activity is not drained and prevents worker from shutting down.
354
+ cancel_on_workflow_completed: matches!(cancel_type, ActivityCancellationType::Abandon)
355
+ && cancel_on_backoff.is_none(),
393
356
  }))
394
357
  .await
395
358
  .unwrap();
359
+ starter.shutdown().await;
396
360
  }
397
361
 
398
362
  #[rstest::rstest]
@@ -448,15 +412,7 @@ async fn x_to_close_timeout(#[case] is_schedule: bool) {
448
412
  Ok(())
449
413
  });
450
414
 
451
- worker
452
- .submit_wf(
453
- wf_name.to_owned(),
454
- wf_name.to_owned(),
455
- vec![],
456
- WorkflowOptions::default(),
457
- )
458
- .await
459
- .unwrap();
415
+ starter.start_with_worker(wf_name, &mut worker).await;
460
416
  worker.run_until_done().await.unwrap();
461
417
  }
462
418
 
@@ -500,15 +456,7 @@ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
500
456
  Result::<(), _>::Err(anyhow!("Oh no I failed!"))
501
457
  });
502
458
 
503
- worker
504
- .submit_wf(
505
- wf_name.to_owned(),
506
- wf_name.to_owned(),
507
- vec![],
508
- WorkflowOptions::default(),
509
- )
510
- .await
511
- .unwrap();
459
+ starter.start_with_worker(wf_name, &mut worker).await;
512
460
  worker.run_until_done().await.unwrap();
513
461
  // 3 attempts b/c first backoff is very small, then the next 2 attempts take at least 2 seconds
514
462
  // b/c of timer backoff.
@@ -518,10 +466,7 @@ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
518
466
  #[rstest::rstest]
519
467
  #[tokio::test]
520
468
  async fn eviction_wont_make_local_act_get_dropped(#[values(true, false)] short_wft_timeout: bool) {
521
- let wf_name = format!(
522
- "eviction_wont_make_local_act_get_dropped_{}",
523
- short_wft_timeout
524
- );
469
+ let wf_name = format!("eviction_wont_make_local_act_get_dropped_{short_wft_timeout}");
525
470
  let mut starter = CoreWfStarter::new(&wf_name);
526
471
  starter.max_cached_workflows(0);
527
472
  let mut worker = starter.worker().await;
@@ -587,15 +532,7 @@ async fn timer_backoff_concurrent_with_non_timer_backoff() {
587
532
  Result::<(), _>::Err(anyhow!("Oh no I failed!"))
588
533
  });
589
534
 
590
- worker
591
- .submit_wf(
592
- wf_name.to_owned(),
593
- wf_name.to_owned(),
594
- vec![],
595
- WorkflowOptions::default(),
596
- )
597
- .await
598
- .unwrap();
535
+ starter.start_with_worker(wf_name, &mut worker).await;
599
536
  worker.run_until_done().await.unwrap();
600
537
  }
601
538
 
@@ -626,7 +563,7 @@ async fn repro_nondeterminism_with_timer_bug() {
626
563
  _ = r1 => {
627
564
  t1.cancel(&ctx);
628
565
  },
629
- };
566
+ }
630
567
  ctx.timer(Duration::from_secs(1)).await;
631
568
  Ok(().into())
632
569
  });
@@ -651,85 +588,6 @@ async fn repro_nondeterminism_with_timer_bug() {
651
588
  .unwrap();
652
589
  }
653
590
 
654
- async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
655
- ctx.local_activity(LocalActivityOptions {
656
- activity_type: "delay".to_string(),
657
- input: "hi".as_json_payload().expect("serializes fine"),
658
- retry_policy: RetryPolicy {
659
- initial_interval: Some(prost_dur!(from_micros(15))),
660
- backoff_coefficient: 1_000.,
661
- maximum_interval: Some(prost_dur!(from_millis(1500))),
662
- maximum_attempts: 4,
663
- non_retryable_error_types: vec![],
664
- },
665
- timer_backoff_threshold: Some(Duration::from_secs(1)),
666
- ..Default::default()
667
- })
668
- .await;
669
- ctx.activity(ActivityOptions {
670
- activity_type: "delay".to_string(),
671
- start_to_close_timeout: Some(Duration::from_secs(20)),
672
- input: "hi!".as_json_payload().expect("serializes fine"),
673
- ..Default::default()
674
- })
675
- .await;
676
- Ok(().into())
677
- }
678
-
679
- // Expensive to run - worth enabling on a stress/regression pipeline.
680
- #[ignore]
681
- #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
682
- async fn evict_while_la_running_no_interference() {
683
- let wf_name = "evict_while_la_running_no_interference";
684
- let mut starter = CoreWfStarter::new(wf_name);
685
- starter.max_local_at(20);
686
- starter.max_cached_workflows(20);
687
- let mut worker = starter.worker().await;
688
-
689
- worker.register_wf(wf_name.to_owned(), la_problem_workflow);
690
- worker.register_activity("delay", |_: ActContext, _: String| async {
691
- tokio::time::sleep(Duration::from_secs(15)).await;
692
- Ok(())
693
- });
694
-
695
- let client = starter.get_client().await;
696
- let subfs = FuturesUnordered::new();
697
- for i in 1..100 {
698
- let wf_id = format!("{}-{}", wf_name, i);
699
- let run_id = worker
700
- .submit_wf(
701
- &wf_id,
702
- wf_name.to_owned(),
703
- vec![],
704
- WorkflowOptions::default(),
705
- )
706
- .await
707
- .unwrap();
708
- let cw = worker.core_worker.clone();
709
- let client = client.clone();
710
- subfs.push(async move {
711
- // Evict the workflow
712
- tokio::time::sleep(Duration::from_secs(1)).await;
713
- cw.request_workflow_eviction(&run_id);
714
- // Wake up workflow by sending signal
715
- client
716
- .signal_workflow_execution(
717
- wf_id,
718
- run_id.clone(),
719
- "whaatever".to_string(),
720
- None,
721
- None,
722
- )
723
- .await
724
- .unwrap();
725
- });
726
- }
727
- let runf = async {
728
- worker.run_until_done().await.unwrap();
729
- };
730
- tokio::join!(subfs.collect::<Vec<_>>(), runf);
731
- }
732
-
733
591
  #[rstest::rstest]
734
592
  #[tokio::test]
735
593
  async fn weird_la_nondeterminism_repro(#[values(true, false)] fix_hist: bool) {
@@ -771,7 +629,6 @@ async fn second_weird_la_nondeterminism_repro() {
771
629
  // Chop off uninteresting ending
772
630
  hist.events.truncate(24);
773
631
  let mut thb = TestHistoryBuilder::from_history(hist.events);
774
- // thb.add_workflow_task_completed();
775
632
  thb.add_workflow_execution_completed();
776
633
  hist = thb.get_full_history_info().unwrap().into();
777
634
 
@@ -786,3 +643,27 @@ async fn second_weird_la_nondeterminism_repro() {
786
643
  });
787
644
  worker.run().await.unwrap();
788
645
  }
646
+
647
+ #[tokio::test]
648
+ async fn third_weird_la_nondeterminism_repro() {
649
+ init_integ_telem();
650
+ let mut hist = history_from_proto_binary(
651
+ "histories/evict_while_la_running_no_interference-16_history.bin",
652
+ )
653
+ .await
654
+ .unwrap();
655
+ let mut thb = TestHistoryBuilder::from_history(hist.events);
656
+ thb.add_workflow_task_scheduled_and_started();
657
+ hist = thb.get_full_history_info().unwrap().into();
658
+
659
+ let mut worker = replay_sdk_worker([HistoryForReplay::new(hist, "fake".to_owned())]);
660
+ worker.register_wf(
661
+ "evict_while_la_running_no_interference",
662
+ la_problem_workflow,
663
+ );
664
+ worker.register_activity("delay", |_: ActContext, _: String| async {
665
+ tokio::time::sleep(Duration::from_secs(15)).await;
666
+ Ok(())
667
+ });
668
+ worker.run().await.unwrap();
669
+ }
@@ -20,6 +20,7 @@ async fn sends_modify_wf_props() {
20
20
  let wf_name = "can_upsert_memo";
21
21
  let wf_id = Uuid::new_v4();
22
22
  let mut starter = CoreWfStarter::new(wf_name);
23
+ starter.no_remote_activities();
23
24
  let mut worker = starter.worker().await;
24
25
 
25
26
  worker.register_wf(wf_name, memo_upserter);
@@ -2,7 +2,7 @@ use std::{
2
2
  sync::atomic::{AtomicBool, Ordering},
3
3
  time::Duration,
4
4
  };
5
- use temporal_client::WorkflowOptions;
5
+
6
6
  use temporal_sdk::{WfContext, WorkflowResult};
7
7
  use temporal_sdk_core_test_utils::CoreWfStarter;
8
8
 
@@ -27,18 +27,11 @@ pub async fn changes_wf(ctx: WfContext) -> WorkflowResult<()> {
27
27
  async fn writes_change_markers() {
28
28
  let wf_name = "writes_change_markers";
29
29
  let mut starter = CoreWfStarter::new(wf_name);
30
+ starter.no_remote_activities();
30
31
  let mut worker = starter.worker().await;
31
32
  worker.register_wf(wf_name.to_owned(), changes_wf);
32
33
 
33
- worker
34
- .submit_wf(
35
- wf_name.to_owned(),
36
- wf_name.to_owned(),
37
- vec![],
38
- WorkflowOptions::default(),
39
- )
40
- .await
41
- .unwrap();
34
+ starter.start_with_worker(wf_name, &mut worker).await;
42
35
  worker.run_until_done().await.unwrap();
43
36
  }
44
37
 
@@ -67,18 +60,11 @@ pub async fn no_change_then_change_wf(ctx: WfContext) -> WorkflowResult<()> {
67
60
  async fn can_add_change_markers() {
68
61
  let wf_name = "can_add_change_markers";
69
62
  let mut starter = CoreWfStarter::new(wf_name);
63
+ starter.no_remote_activities();
70
64
  let mut worker = starter.worker().await;
71
65
  worker.register_wf(wf_name.to_owned(), no_change_then_change_wf);
72
66
 
73
- worker
74
- .submit_wf(
75
- wf_name.to_owned(),
76
- wf_name.to_owned(),
77
- vec![],
78
- WorkflowOptions::default(),
79
- )
80
- .await
81
- .unwrap();
67
+ starter.start_with_worker(wf_name, &mut worker).await;
82
68
  worker.run_until_done().await.unwrap();
83
69
  }
84
70
 
@@ -97,17 +83,10 @@ pub async fn replay_with_change_marker_wf(ctx: WfContext) -> WorkflowResult<()>
97
83
  async fn replaying_with_patch_marker() {
98
84
  let wf_name = "replaying_with_patch_marker";
99
85
  let mut starter = CoreWfStarter::new(wf_name);
86
+ starter.no_remote_activities();
100
87
  let mut worker = starter.worker().await;
101
88
  worker.register_wf(wf_name.to_owned(), replay_with_change_marker_wf);
102
89
 
103
- worker
104
- .submit_wf(
105
- wf_name.to_owned(),
106
- wf_name.to_owned(),
107
- vec![],
108
- WorkflowOptions::default(),
109
- )
110
- .await
111
- .unwrap();
90
+ starter.start_with_worker(wf_name, &mut worker).await;
112
91
  worker.run_until_done().await.unwrap();
113
92
  }
@@ -129,18 +129,23 @@ async fn replay_using_wf_function() {
129
129
  worker.run().await.unwrap();
130
130
  }
131
131
 
132
+ async fn replay_abrupt_ending(t: TestHistoryBuilder) {
133
+ let func = timers_wf(1);
134
+ let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
135
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
136
+ worker.run().await.unwrap();
137
+ }
132
138
  #[tokio::test]
133
- async fn replay_ok_ending_with_terminated_or_timed_out() {
139
+ async fn replay_ok_ending_with_terminated() {
134
140
  let mut t1 = canned_histories::single_timer("1");
135
141
  t1.add_workflow_execution_terminated();
142
+ replay_abrupt_ending(t1).await;
143
+ }
144
+ #[tokio::test]
145
+ async fn replay_ok_ending_with_timed_out() {
136
146
  let mut t2 = canned_histories::single_timer("1");
137
147
  t2.add_workflow_execution_timed_out();
138
- for t in [t1, t2] {
139
- let func = timers_wf(1);
140
- let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
141
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
142
- worker.run().await.unwrap();
143
- }
148
+ replay_abrupt_ending(t2).await;
144
149
  }
145
150
 
146
151
  #[rstest::rstest]
@@ -14,6 +14,7 @@ const POST_RESET_SIG: &str = "post-reset";
14
14
  async fn reset_workflow() {
15
15
  let wf_name = "reset_me_wf";
16
16
  let mut starter = CoreWfStarter::new(wf_name);
17
+ starter.no_remote_activities();
17
18
  let mut worker = starter.worker().await;
18
19
  worker.fetch_results = false;
19
20
  let notify = Arc::new(Notify::new());
@@ -1,7 +1,9 @@
1
1
  use std::collections::HashMap;
2
2
 
3
3
  use futures::StreamExt;
4
- use temporal_client::{WorkflowClientTrait, WorkflowExecutionInfo, WorkflowOptions};
4
+ use temporal_client::{
5
+ SignalWithStartOptions, WorkflowClientTrait, WorkflowExecutionInfo, WorkflowOptions,
6
+ };
5
7
  use temporal_sdk::{
6
8
  ChildWorkflowOptions, Signal, SignalWorkflowOptions, WfContext, WorkflowResult,
7
9
  };
@@ -32,6 +34,7 @@ async fn signal_sender(ctx: WfContext) -> WorkflowResult<()> {
32
34
  async fn sends_signal_to_missing_wf() {
33
35
  let wf_name = "sends_signal_to_missing_wf";
34
36
  let mut starter = CoreWfStarter::new(wf_name);
37
+ starter.no_remote_activities();
35
38
  let mut worker = starter.worker().await;
36
39
  worker.register_wf(wf_name.to_owned(), signal_sender);
37
40
 
@@ -59,7 +62,6 @@ async fn signal_receiver(ctx: WfContext) -> WorkflowResult<()> {
59
62
 
60
63
  async fn signal_with_create_wf_receiver(ctx: WfContext) -> WorkflowResult<()> {
61
64
  let res = ctx.make_signal_channel(SIGNAME).next().await.unwrap();
62
- println!("HEADER: {:?}", res.headers);
63
65
  assert_eq!(&res.input, &[b"tada".into()]);
64
66
  assert_eq!(
65
67
  *res.headers.get("tupac").expect("tupac header exists"),
@@ -71,6 +73,7 @@ async fn signal_with_create_wf_receiver(ctx: WfContext) -> WorkflowResult<()> {
71
73
  #[tokio::test]
72
74
  async fn sends_signal_to_other_wf() {
73
75
  let mut starter = CoreWfStarter::new("sends_signal_to_other_wf");
76
+ starter.no_remote_activities();
74
77
  let mut worker = starter.worker().await;
75
78
  worker.register_wf("sender", signal_sender);
76
79
  worker.register_wf("receiver", signal_receiver);
@@ -99,24 +102,24 @@ async fn sends_signal_to_other_wf() {
99
102
  #[tokio::test]
100
103
  async fn sends_signal_with_create_wf() {
101
104
  let mut starter = CoreWfStarter::new("sends_signal_with_create_wf");
105
+ starter.no_remote_activities();
102
106
  let mut worker = starter.worker().await;
103
- worker.register_wf("receiversignal", signal_with_create_wf_receiver);
107
+ worker.register_wf("receiver_signal", signal_with_create_wf_receiver);
104
108
 
105
109
  let client = starter.get_client().await;
106
110
  let mut header: HashMap<String, Payload> = HashMap::new();
107
111
  header.insert("tupac".into(), "shakur".into());
112
+ let options = SignalWithStartOptions::builder()
113
+ .task_queue(worker.inner_mut().task_queue())
114
+ .workflow_id("sends_signal_with_create_wf")
115
+ .workflow_type("receiver_signal")
116
+ .signal_name(SIGNAME)
117
+ .signal_input(vec![b"tada".into()].into_payloads())
118
+ .signal_header(header.into())
119
+ .build()
120
+ .unwrap();
108
121
  let res = client
109
- .signal_with_start_workflow_execution(
110
- None,
111
- worker.inner_mut().task_queue().to_owned(),
112
- "sends_signal_with_create_wf".to_owned(),
113
- "receiversignal".to_owned(),
114
- None,
115
- WorkflowOptions::default(),
116
- SIGNAME.to_owned(),
117
- vec![b"tada".into()].into_payloads(),
118
- Some(header.into()),
119
- )
122
+ .signal_with_start_workflow_execution(options, WorkflowOptions::default())
120
123
  .await
121
124
  .expect("request succeeds.qed");
122
125
 
@@ -150,6 +153,7 @@ async fn signals_child(ctx: WfContext) -> WorkflowResult<()> {
150
153
  #[tokio::test]
151
154
  async fn sends_signal_to_child() {
152
155
  let mut starter = CoreWfStarter::new("sends_signal_to_child");
156
+ starter.no_remote_activities();
153
157
  let mut worker = starter.worker().await;
154
158
  worker.register_wf("child_signaler", signals_child);
155
159
  worker.register_wf("child_receiver", signal_receiver);
@@ -12,19 +12,12 @@ use tokio::sync::Barrier;
12
12
  async fn timer_workflow_not_sticky() {
13
13
  let wf_name = "timer_wf_not_sticky";
14
14
  let mut starter = CoreWfStarter::new(wf_name);
15
+ starter.no_remote_activities();
15
16
  starter.max_cached_workflows(0);
16
17
  let mut worker = starter.worker().await;
17
18
  worker.register_wf(wf_name.to_owned(), timer_wf);
18
19
 
19
- worker
20
- .submit_wf(
21
- wf_name.to_owned(),
22
- wf_name.to_owned(),
23
- vec![],
24
- WorkflowOptions::default(),
25
- )
26
- .await
27
- .unwrap();
20
+ starter.start_with_worker(wf_name, &mut worker).await;
28
21
  worker.run_until_done().await.unwrap();
29
22
  }
30
23
 
@@ -47,19 +40,12 @@ async fn timer_workflow_timeout_on_sticky() {
47
40
  // on a not-sticky queue
48
41
  let wf_name = "timer_workflow_timeout_on_sticky";
49
42
  let mut starter = CoreWfStarter::new(wf_name);
50
- starter.wft_timeout(Duration::from_secs(2));
43
+ starter.no_remote_activities();
44
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(2));
51
45
  let mut worker = starter.worker().await;
52
46
  worker.register_wf(wf_name.to_owned(), timer_timeout_wf);
53
47
 
54
- worker
55
- .submit_wf(
56
- wf_name.to_owned(),
57
- wf_name.to_owned(),
58
- vec![],
59
- WorkflowOptions::default(),
60
- )
61
- .await
62
- .unwrap();
48
+ starter.start_with_worker(wf_name, &mut worker).await;
63
49
  worker.run_until_done().await.unwrap();
64
50
  // If it didn't run twice it didn't time out
65
51
  assert_eq!(RUN_CT.load(Ordering::SeqCst), 2);
@@ -69,7 +55,7 @@ async fn timer_workflow_timeout_on_sticky() {
69
55
  async fn cache_miss_ok() {
70
56
  let wf_name = "cache_miss_ok";
71
57
  let mut starter = CoreWfStarter::new(wf_name);
72
- starter.max_wft(1);
58
+ starter.no_remote_activities().max_wft(1);
73
59
  let mut worker = starter.worker().await;
74
60
 
75
61
  let barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));