@temporalio/core-bridge 1.15.0 → 1.16.1

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 (209) hide show
  1. package/Cargo.lock +172 -70
  2. package/lib/native.d.ts +1 -1
  3. package/package.json +2 -2
  4. package/releases/aarch64-apple-darwin/index.node +0 -0
  5. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  6. package/releases/x86_64-apple-darwin/index.node +0 -0
  7. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  8. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  9. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  10. package/sdk-core/AGENTS.md +41 -30
  11. package/sdk-core/Cargo.toml +3 -0
  12. package/sdk-core/README.md +15 -9
  13. package/sdk-core/crates/client/Cargo.toml +4 -0
  14. package/sdk-core/crates/client/README.md +139 -0
  15. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  16. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  17. package/sdk-core/crates/client/src/errors.rs +294 -0
  18. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +280 -159
  19. package/sdk-core/crates/client/src/lib.rs +920 -1326
  20. package/sdk-core/crates/client/src/metrics.rs +24 -33
  21. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  22. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  23. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  24. package/sdk-core/crates/client/src/retry.rs +99 -54
  25. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +1 -1
  26. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  27. package/sdk-core/crates/common/Cargo.toml +61 -2
  28. package/sdk-core/crates/common/build.rs +742 -12
  29. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  30. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  31. package/sdk-core/crates/common/protos/api_upstream/buf.yaml +0 -3
  32. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  33. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +1166 -770
  34. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +1243 -750
  35. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +2 -2
  36. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -3
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +4 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +16 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -6
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +88 -33
  43. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +4 -2
  44. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  45. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +5 -5
  46. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  47. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  48. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  49. package/sdk-core/crates/common/src/lib.rs +15 -211
  50. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  51. package/sdk-core/crates/common/src/priority.rs +110 -0
  52. package/sdk-core/crates/common/src/protos/canned_histories.rs +3 -0
  53. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  54. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  55. package/sdk-core/crates/common/src/protos/mod.rs +122 -27
  56. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  57. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  58. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +5 -7
  59. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  60. package/sdk-core/crates/common/src/telemetry/metrics.rs +268 -223
  61. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  62. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  63. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  64. package/sdk-core/crates/common/src/telemetry.rs +264 -4
  65. package/sdk-core/crates/common/src/worker.rs +68 -603
  66. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  67. package/sdk-core/crates/macros/Cargo.toml +5 -1
  68. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  69. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  70. package/sdk-core/crates/macros/src/lib.rs +138 -512
  71. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  72. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  73. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  74. package/sdk-core/crates/sdk/README.md +415 -0
  75. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  76. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  77. package/sdk-core/crates/sdk/src/lib.rs +757 -442
  78. package/sdk-core/crates/sdk/src/workflow_context/options.rs +45 -35
  79. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  80. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  81. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  82. package/sdk-core/crates/sdk-core/Cargo.toml +57 -64
  83. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +41 -35
  84. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  85. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  86. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  87. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +13 -15
  88. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  89. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  90. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  91. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +493 -26
  92. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +4 -8
  93. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +7 -7
  94. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  95. package/sdk-core/crates/sdk-core/src/lib.rs +41 -111
  96. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  97. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +118 -19
  98. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  99. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  100. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +179 -196
  101. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -280
  102. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +6 -9
  103. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  104. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  105. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  106. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +9 -5
  107. package/sdk-core/crates/sdk-core/src/worker/client.rs +103 -81
  108. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +7 -11
  109. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1124 -229
  110. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +145 -23
  111. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  112. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  113. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +13 -13
  114. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +28 -8
  115. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  116. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  117. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +19 -4
  118. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +14 -18
  119. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +4 -6
  120. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  121. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  122. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  123. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  124. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  125. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  126. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  127. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  128. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  129. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  130. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  131. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  132. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  133. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  134. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  135. package/sdk-core/crates/sdk-core/tests/common/mod.rs +241 -196
  136. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  137. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +3 -5
  138. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -64
  139. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +298 -252
  140. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  141. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  142. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  143. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +16 -12
  144. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +48 -40
  145. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +327 -255
  146. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  147. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +147 -126
  148. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  149. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -453
  150. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  151. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +360 -231
  152. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +248 -185
  153. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -43
  154. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  155. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +428 -315
  156. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -56
  157. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -28
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -243
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +101 -42
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -147
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -28
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1036
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -41
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +397 -238
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +414 -189
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +154 -137
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -105
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -38
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -40
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -54
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +363 -226
  175. package/sdk-core/crates/sdk-core/tests/main.rs +17 -15
  176. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +207 -152
  177. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +65 -34
  178. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  179. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  180. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  181. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  182. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  183. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  184. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  185. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  186. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  187. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  188. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +7 -1
  189. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +14 -14
  190. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +83 -74
  191. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +9 -14
  192. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +1 -2
  193. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +13 -13
  194. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +6 -6
  195. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +3 -4
  196. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +62 -75
  197. package/sdk-core/rustfmt.toml +2 -1
  198. package/src/client.rs +205 -318
  199. package/src/metrics.rs +22 -30
  200. package/src/runtime.rs +4 -5
  201. package/src/worker.rs +16 -19
  202. package/ts/native.ts +1 -1
  203. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  204. package/sdk-core/crates/common/src/errors.rs +0 -85
  205. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  206. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  207. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  208. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  209. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -1,12 +1,17 @@
1
- use crate::common::{CoreWfStarter, WorkflowHandleExt, mock_sdk, mock_sdk_cfg};
1
+ use crate::common::{
2
+ CoreWfStarter, WorkflowHandleExt, activity_functions::StdActivities, mock_sdk, mock_sdk_cfg,
3
+ };
2
4
  use std::{
3
- sync::atomic::{AtomicBool, AtomicUsize, Ordering},
5
+ sync::{
6
+ Arc,
7
+ atomic::{AtomicBool, AtomicUsize, Ordering},
8
+ },
4
9
  time::Duration,
5
10
  };
6
- use temporalio_client::WorkflowOptions;
11
+ use temporalio_client::WorkflowStartOptions;
7
12
  use temporalio_common::{
8
13
  protos::{
9
- DEFAULT_ACTIVITY_TYPE, TestHistoryBuilder, canned_histories,
14
+ TestHistoryBuilder, canned_histories,
10
15
  coresdk::AsJsonPayloadExt,
11
16
  temporal::api::{
12
17
  enums::v1::{EventType, WorkflowTaskFailedCause},
@@ -15,85 +20,121 @@ use temporalio_common::{
15
20
  },
16
21
  worker::WorkerTaskTypes,
17
22
  };
23
+ use temporalio_macros::{workflow, workflow_methods};
18
24
  use temporalio_sdk::{
19
- ActContext, ActivityOptions, ChildWorkflowOptions, LocalActivityOptions, WfContext,
20
- WorkflowResult,
25
+ ActivityOptions, ChildWorkflowOptions, LocalActivityOptions, WorkflowContext, WorkflowResult,
21
26
  };
22
27
  use temporalio_sdk_core::{
23
28
  replay::DEFAULT_WORKFLOW_TYPE,
24
29
  test_help::{CoreInternalFlags, MockPollCfg, ResponseType, mock_worker_client},
25
30
  };
26
31
 
27
- static RUN_CT: AtomicUsize = AtomicUsize::new(1);
32
+ #[workflow]
33
+ pub(crate) struct TimerWfNondeterministic {
34
+ run_ct: Arc<AtomicUsize>,
35
+ }
28
36
 
29
- pub(crate) async fn timer_wf_nondeterministic(ctx: WfContext) -> WorkflowResult<()> {
30
- let run_ct = RUN_CT.fetch_add(1, Ordering::Relaxed);
37
+ #[workflow_methods(factory_only)]
38
+ impl TimerWfNondeterministic {
39
+ #[run]
40
+ pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
41
+ let run_ct = ctx.state(|wf| wf.run_ct.fetch_add(1, Ordering::Relaxed));
31
42
 
32
- match run_ct {
33
- 1 | 3 => {
34
- // If we have not run yet or are on the third attempt, schedule a timer
35
- ctx.timer(Duration::from_secs(1)).await;
36
- if run_ct == 1 {
37
- // on first attempt we need to blow up after the timer fires so we will replay
38
- panic!("dying on purpose");
43
+ match run_ct {
44
+ 1 | 3 => {
45
+ ctx.timer(Duration::from_secs(1)).await;
46
+ if run_ct == 1 {
47
+ panic!("dying on purpose");
48
+ }
39
49
  }
50
+ 2 => {
51
+ ctx.start_activity(StdActivities::default, (), ActivityOptions::default())
52
+ .await
53
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
54
+ }
55
+ _ => panic!("Ran too many times"),
40
56
  }
41
- 2 => {
42
- // On the second attempt we should cause a nondeterminism error
43
- ctx.activity(ActivityOptions {
44
- activity_type: "whatever".to_string(),
45
- ..Default::default()
46
- })
47
- .await;
48
- }
49
- _ => panic!("Ran too many times"),
57
+ Ok(())
50
58
  }
51
- Ok(().into())
52
59
  }
53
60
 
54
61
  #[tokio::test]
55
62
  async fn test_determinism_error_then_recovers() {
56
63
  let wf_name = "test_determinism_error_then_recovers";
57
64
  let mut starter = CoreWfStarter::new(wf_name);
58
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
65
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
59
66
  let mut worker = starter.worker().await;
60
67
 
61
- worker.register_wf(wf_name.to_owned(), timer_wf_nondeterministic);
62
- starter.start_with_worker(wf_name, &mut worker).await;
68
+ let run_ct = Arc::new(AtomicUsize::new(1));
69
+ let run_ct_clone = run_ct.clone();
70
+ worker.register_workflow_with_factory(move || TimerWfNondeterministic {
71
+ run_ct: run_ct_clone.clone(),
72
+ });
73
+ let task_queue = starter.get_task_queue().to_owned();
74
+ worker
75
+ .submit_workflow(
76
+ TimerWfNondeterministic::run,
77
+ (),
78
+ WorkflowStartOptions::new(task_queue, starter.get_task_queue().to_owned()).build(),
79
+ )
80
+ .await
81
+ .unwrap();
63
82
  worker.run_until_done().await.unwrap();
64
- // 4 because we still add on the 3rd and final attempt
65
- assert_eq!(RUN_CT.load(Ordering::Relaxed), 4);
83
+ assert_eq!(run_ct.load(Ordering::Relaxed), 4);
84
+ }
85
+
86
+ #[workflow]
87
+ struct TaskFailReplayWf {
88
+ did_fail: Arc<AtomicBool>,
89
+ }
90
+
91
+ #[workflow_methods(factory_only)]
92
+ impl TaskFailReplayWf {
93
+ #[run]
94
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
95
+ if ctx.state(|wf| wf.did_fail.load(Ordering::Relaxed)) {
96
+ assert!(ctx.is_replaying());
97
+ }
98
+ let _ = ctx
99
+ .start_activity(
100
+ StdActivities::echo,
101
+ "hi!".to_string(),
102
+ ActivityOptions {
103
+ start_to_close_timeout: Some(Duration::from_secs(2)),
104
+ ..Default::default()
105
+ },
106
+ )
107
+ .await;
108
+ if !ctx.state(|wf| wf.did_fail.load(Ordering::Relaxed)) {
109
+ ctx.state(|wf| wf.did_fail.store(true, Ordering::Relaxed));
110
+ panic!("Die on purpose");
111
+ }
112
+ Ok(())
113
+ }
66
114
  }
67
115
 
68
116
  #[tokio::test]
69
117
  async fn task_fail_causes_replay_unset_too_soon() {
70
118
  let wf_name = "task_fail_causes_replay_unset_too_soon";
71
119
  let mut starter = CoreWfStarter::new(wf_name);
120
+ starter.sdk_config.register_activities(StdActivities);
72
121
  let mut worker = starter.worker().await;
73
122
 
74
- static DID_FAIL: AtomicBool = AtomicBool::new(false);
75
- worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
76
- if DID_FAIL.load(Ordering::Relaxed) {
77
- assert!(ctx.is_replaying());
78
- }
79
- ctx.activity(ActivityOptions {
80
- activity_type: "echo".to_string(),
81
- input: "hi!".as_json_payload().expect("serializes fine"),
82
- start_to_close_timeout: Some(Duration::from_secs(2)),
83
- ..Default::default()
84
- })
85
- .await;
86
- if !DID_FAIL.load(Ordering::Relaxed) {
87
- DID_FAIL.store(true, Ordering::Relaxed);
88
- panic!("Die on purpose");
89
- }
90
- Ok(().into())
91
- });
92
- worker.register_activity("echo", |_ctx: ActContext, echo_me: String| async move {
93
- Ok(echo_me)
123
+ let did_fail = Arc::new(AtomicBool::new(false));
124
+ let did_fail_clone = did_fail.clone();
125
+ worker.register_workflow_with_factory(move || TaskFailReplayWf {
126
+ did_fail: did_fail_clone.clone(),
94
127
  });
95
128
 
96
- let handle = starter.start_with_worker(wf_name, &mut worker).await;
129
+ let task_queue = starter.get_task_queue().to_owned();
130
+ let handle = worker
131
+ .submit_workflow(
132
+ TaskFailReplayWf::run,
133
+ (),
134
+ WorkflowStartOptions::new(task_queue, starter.get_task_queue().to_owned()).build(),
135
+ )
136
+ .await
137
+ .unwrap();
97
138
 
98
139
  worker.run_until_done().await.unwrap();
99
140
  handle
@@ -102,17 +143,27 @@ async fn task_fail_causes_replay_unset_too_soon() {
102
143
  .unwrap();
103
144
  }
104
145
 
105
- async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
106
- static DID_FAIL: AtomicBool = AtomicBool::new(false);
146
+ #[workflow]
147
+ struct TimerWfFailsOnce {
148
+ did_fail: Arc<AtomicBool>,
149
+ }
107
150
 
108
- ctx.timer(Duration::from_secs(1)).await;
109
- if DID_FAIL
110
- .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
111
- .is_ok()
112
- {
113
- panic!("Ahh");
151
+ #[workflow_methods(factory_only)]
152
+ impl TimerWfFailsOnce {
153
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
154
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
155
+ ctx.timer(Duration::from_secs(1)).await;
156
+ if ctx
157
+ .state(|wf| {
158
+ wf.did_fail
159
+ .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
160
+ })
161
+ .is_ok()
162
+ {
163
+ panic!("Ahh");
164
+ }
165
+ Ok(())
114
166
  }
115
- Ok(().into())
116
167
  }
117
168
 
118
169
  /// Verifies that workflow panics (which in this case the Rust SDK turns into workflow activation
@@ -135,19 +186,39 @@ async fn test_panic_wf_task_rejected_properly() {
135
186
  });
136
187
  let mut worker = mock_sdk(mh);
137
188
 
138
- worker.register_wf(wf_type.to_owned(), timer_wf_fails_once);
189
+ let did_fail = Arc::new(AtomicBool::new(false));
190
+ worker.register_workflow_with_factory(move || TimerWfFailsOnce {
191
+ did_fail: did_fail.clone(),
192
+ });
193
+ let task_queue = "fake_tq".to_owned();
139
194
  worker
140
195
  .submit_wf(
141
- wf_id.to_owned(),
142
196
  wf_type.to_owned(),
143
197
  vec![],
144
- WorkflowOptions::default(),
198
+ WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
145
199
  )
146
200
  .await
147
201
  .unwrap();
148
202
  worker.run_until_done().await.unwrap();
149
203
  }
150
204
 
205
+ #[workflow]
206
+ struct NondeterministicTimerWf {
207
+ started_count: Arc<AtomicUsize>,
208
+ }
209
+
210
+ #[workflow_methods(factory_only)]
211
+ impl NondeterministicTimerWf {
212
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
213
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
214
+ if ctx.state(|wf| wf.started_count.fetch_add(1, Ordering::Relaxed)) == 0 {
215
+ ctx.timer(Duration::from_secs(1)).await;
216
+ }
217
+ ctx.timer(Duration::from_secs(1)).await;
218
+ Ok(())
219
+ }
220
+ }
221
+
151
222
  /// Verifies nondeterministic behavior in workflows results in automatic WFT failure with the
152
223
  /// appropriate nondeterminism cause.
153
224
  #[rstest::rstest]
@@ -162,11 +233,9 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
162
233
  let mut mh = MockPollCfg::from_resp_batches(
163
234
  wf_id,
164
235
  t,
165
- // Two polls are needed, since the first will fail
166
236
  [ResponseType::AllHistory, ResponseType::AllHistory],
167
237
  mock,
168
238
  );
169
- // We should see one wft failure which has nondeterminism cause
170
239
  mh.num_expected_fails = 1;
171
240
  mh.expect_fail_wft_matcher =
172
241
  Box::new(|_, cause, _| matches!(cause, WorkflowTaskFailedCause::NonDeterministicError));
@@ -176,32 +245,73 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
176
245
  }
177
246
  });
178
247
 
179
- let started_count: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
180
- worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
181
- // The workflow is replaying all of history, so the when it schedules an extra timer it
182
- // should not have, it causes a nondeterminism error.
183
- if started_count.fetch_add(1, Ordering::Relaxed) == 0 {
184
- ctx.timer(Duration::from_secs(1)).await;
185
- }
186
- ctx.timer(Duration::from_secs(1)).await;
187
- Ok(().into())
248
+ let started_count = Arc::new(AtomicUsize::new(0));
249
+ let count_clone = started_count.clone();
250
+ worker.register_workflow_with_factory(move || NondeterministicTimerWf {
251
+ started_count: count_clone.clone(),
188
252
  });
189
253
 
254
+ let task_queue = "fake_tq".to_owned();
190
255
  worker
191
256
  .submit_wf(
192
- wf_id.to_owned(),
193
257
  wf_type.to_owned(),
194
258
  vec![],
195
- WorkflowOptions::default(),
259
+ WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
196
260
  )
197
261
  .await
198
262
  .unwrap();
199
263
  worker.run_until_done().await.unwrap();
200
- // Started count is two since we start, restart once due to error, then we unblock the real
201
- // timer and proceed without restarting
202
264
  assert_eq!(2, started_count.load(Ordering::Relaxed));
203
265
  }
204
266
 
267
+ #[workflow]
268
+ #[derive(Default)]
269
+ struct ActivityIdOrTypeChangeWf;
270
+
271
+ #[workflow_methods]
272
+ impl ActivityIdOrTypeChangeWf {
273
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
274
+ async fn run(
275
+ ctx: &mut WorkflowContext<Self>,
276
+ (id_change, local_act): (bool, bool),
277
+ ) -> WorkflowResult<()> {
278
+ if local_act {
279
+ if id_change {
280
+ ctx.start_local_activity(
281
+ StdActivities::default,
282
+ (),
283
+ LocalActivityOptions {
284
+ activity_id: Some("I'm bad and wrong!".to_string()),
285
+ ..Default::default()
286
+ },
287
+ )
288
+ .await
289
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
290
+ } else {
291
+ ctx.start_local_activity(StdActivities::no_op, (), Default::default())
292
+ .await
293
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
294
+ }
295
+ } else if id_change {
296
+ ctx.start_activity(
297
+ StdActivities::default,
298
+ (),
299
+ ActivityOptions {
300
+ activity_id: Some("I'm bad and wrong!".to_string()),
301
+ ..Default::default()
302
+ },
303
+ )
304
+ .await
305
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
306
+ } else {
307
+ ctx.start_activity(StdActivities::no_op, (), ActivityOptions::default())
308
+ .await
309
+ .map_err(|e| anyhow::anyhow!("{e}"))?;
310
+ }
311
+ Ok(())
312
+ }
313
+ }
314
+
205
315
  #[rstest::rstest]
206
316
  #[tokio::test]
207
317
  async fn activity_id_or_type_change_is_nondeterministic(
@@ -217,15 +327,14 @@ async fn activity_id_or_type_change_is_nondeterministic(
217
327
  canned_histories::single_activity("1")
218
328
  };
219
329
  t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
330
+ t.set_wf_input((id_change, local_act).as_json_payload().unwrap());
220
331
  let mock = mock_worker_client();
221
332
  let mut mh = MockPollCfg::from_resp_batches(
222
333
  wf_id,
223
334
  t,
224
- // Two polls are needed, since the first will fail
225
335
  [ResponseType::AllHistory, ResponseType::AllHistory],
226
336
  mock,
227
337
  );
228
- // We should see one wft failure which has nondeterminism cause
229
338
  mh.num_expected_fails = 1;
230
339
  mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
231
340
  let should_contain = if id_change {
@@ -244,52 +353,47 @@ async fn activity_id_or_type_change_is_nondeterministic(
244
353
  cfg.max_cached_workflows = 2;
245
354
  }
246
355
  });
356
+ worker.register_workflow::<ActivityIdOrTypeChangeWf>();
247
357
 
248
- worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
249
- if local_act {
250
- ctx.local_activity(if id_change {
251
- LocalActivityOptions {
252
- activity_id: Some("I'm bad and wrong!".to_string()),
253
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
254
- ..Default::default()
255
- }
256
- } else {
257
- LocalActivityOptions {
258
- activity_type: "not the default act type".to_string(),
259
- ..Default::default()
260
- }
261
- })
262
- .await;
263
- } else {
264
- ctx.activity(if id_change {
265
- ActivityOptions {
266
- activity_id: Some("I'm bad and wrong!".to_string()),
267
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
268
- ..Default::default()
269
- }
270
- } else {
271
- ActivityOptions {
272
- activity_type: "not the default act type".to_string(),
273
- ..Default::default()
274
- }
275
- })
276
- .await;
277
- }
278
- Ok(().into())
279
- });
280
-
358
+ let task_queue = "fake_tq".to_owned();
281
359
  worker
282
360
  .submit_wf(
283
- wf_id.to_owned(),
284
361
  wf_type.to_owned(),
285
- vec![],
286
- WorkflowOptions::default(),
362
+ vec![(id_change, local_act).as_json_payload().unwrap()],
363
+ WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
287
364
  )
288
365
  .await
289
366
  .unwrap();
290
367
  worker.run_until_done().await.unwrap();
291
368
  }
292
369
 
370
+ #[workflow]
371
+ #[derive(Default)]
372
+ struct ChildWfIdOrTypeChangeWf;
373
+
374
+ #[workflow_methods]
375
+ impl ChildWfIdOrTypeChangeWf {
376
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
377
+ async fn run(ctx: &mut WorkflowContext<Self>, id_change: bool) -> WorkflowResult<()> {
378
+ ctx.child_workflow(if id_change {
379
+ ChildWorkflowOptions {
380
+ workflow_id: "I'm bad and wrong!".to_string(),
381
+ workflow_type: "child".to_string(),
382
+ ..Default::default()
383
+ }
384
+ } else {
385
+ ChildWorkflowOptions {
386
+ workflow_id: "1".to_string(),
387
+ workflow_type: "not the child wf type".to_string(),
388
+ ..Default::default()
389
+ }
390
+ })
391
+ .start()
392
+ .await;
393
+ Ok(())
394
+ }
395
+ }
396
+
293
397
  #[rstest::rstest]
294
398
  #[tokio::test]
295
399
  async fn child_wf_id_or_type_change_is_nondeterministic(
@@ -300,15 +404,14 @@ async fn child_wf_id_or_type_change_is_nondeterministic(
300
404
  let wf_type = DEFAULT_WORKFLOW_TYPE;
301
405
  let mut t = canned_histories::single_child_workflow("1");
302
406
  t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
407
+ t.set_wf_input(id_change.as_json_payload().unwrap());
303
408
  let mock = mock_worker_client();
304
409
  let mut mh = MockPollCfg::from_resp_batches(
305
410
  wf_id,
306
411
  t,
307
- // Two polls are needed, since the first will fail
308
412
  [ResponseType::AllHistory, ResponseType::AllHistory],
309
413
  mock,
310
414
  );
311
- // We should see one wft failure which has nondeterminism cause
312
415
  mh.num_expected_fails = 1;
313
416
  mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
314
417
  let should_contain = if id_change {
@@ -328,37 +431,34 @@ async fn child_wf_id_or_type_change_is_nondeterministic(
328
431
  }
329
432
  });
330
433
 
331
- worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
332
- ctx.child_workflow(if id_change {
333
- ChildWorkflowOptions {
334
- workflow_id: "I'm bad and wrong!".to_string(),
335
- workflow_type: DEFAULT_ACTIVITY_TYPE.to_string(),
336
- ..Default::default()
337
- }
338
- } else {
339
- ChildWorkflowOptions {
340
- workflow_id: "1".to_string(),
341
- workflow_type: "not the child wf type".to_string(),
342
- ..Default::default()
343
- }
344
- })
345
- .start(&ctx)
346
- .await;
347
- Ok(().into())
348
- });
434
+ worker.register_workflow::<ChildWfIdOrTypeChangeWf>();
349
435
 
436
+ let task_queue = "fake_tq".to_owned();
350
437
  worker
351
438
  .submit_wf(
352
- wf_id.to_owned(),
353
439
  wf_type.to_owned(),
354
- vec![],
355
- WorkflowOptions::default(),
440
+ vec![id_change.as_json_payload().unwrap()],
441
+ WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
356
442
  )
357
443
  .await
358
444
  .unwrap();
359
445
  worker.run_until_done().await.unwrap();
360
446
  }
361
447
 
448
+ #[workflow]
449
+ #[derive(Default)]
450
+ struct ReproChannelMissingWf;
451
+
452
+ #[workflow_methods]
453
+ impl ReproChannelMissingWf {
454
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
455
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
456
+ ctx.patched("wrongid");
457
+ ctx.timer(Duration::from_secs(1)).await;
458
+ Ok(())
459
+ }
460
+ }
461
+
362
462
  /// Repros a situation where if, upon completing a task there is some internal error which causes
363
463
  /// us to want to auto-fail the workflow task while there is also an outstanding eviction, the wf
364
464
  /// would get evicted but then try to send some info down the completion channel afterward, causing
@@ -384,18 +484,14 @@ async fn repro_channel_missing_because_nondeterminism() {
384
484
  cfg.ignore_evicts_on_shutdown = false;
385
485
  });
386
486
 
387
- worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
388
- ctx.patched("wrongid");
389
- ctx.timer(Duration::from_secs(1)).await;
390
- Ok(().into())
391
- });
487
+ worker.register_workflow::<ReproChannelMissingWf>();
392
488
 
489
+ let task_queue = "fake_tq".to_owned();
393
490
  worker
394
491
  .submit_wf(
395
- wf_id.to_owned(),
396
492
  wf_type.to_owned(),
397
493
  vec![],
398
- WorkflowOptions::default(),
494
+ WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
399
495
  )
400
496
  .await
401
497
  .unwrap();