@temporalio/core-bridge 1.15.0 → 1.16.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 (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 +16 -3
  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 +340 -188
  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 +15 -18
  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
@@ -7,59 +7,73 @@ use std::{
7
7
  },
8
8
  time::Duration,
9
9
  };
10
- use temporalio_client::WorkflowClientTrait;
11
- use temporalio_common::protos::{
12
- DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, VERSION_SEARCH_ATTR_KEY,
13
- constants::PATCH_MARKER_NAME,
14
- coresdk::{
15
- AsJsonPayloadExt, FromJsonPayloadExt,
16
- common::decode_change_marker_details,
17
- workflow_activation::{NotifyHasPatch, WorkflowActivationJob, workflow_activation_job},
18
- },
19
- temporal::api::{
20
- command::v1::{
21
- RecordMarkerCommandAttributes, ScheduleActivityTaskCommandAttributes,
22
- UpsertWorkflowSearchAttributesCommandAttributes, command::Attributes,
10
+ use temporalio_client::{WorkflowSignalOptions, WorkflowStartOptions};
11
+ use temporalio_common::{
12
+ data_converters::RawValue,
13
+ protos::{
14
+ DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, VERSION_SEARCH_ATTR_KEY,
15
+ constants::PATCH_MARKER_NAME,
16
+ coresdk::{
17
+ AsJsonPayloadExt, FromJsonPayloadExt,
18
+ common::decode_change_marker_details,
19
+ workflow_activation::{NotifyHasPatch, WorkflowActivationJob, workflow_activation_job},
23
20
  },
24
- common::v1::ActivityType,
25
- enums::v1::{CommandType, EventType},
26
- history::v1::{
27
- ActivityTaskCompletedEventAttributes, ActivityTaskScheduledEventAttributes,
28
- ActivityTaskStartedEventAttributes, TimerFiredEventAttributes,
21
+ temporal::api::{
22
+ command::v1::{
23
+ RecordMarkerCommandAttributes, ScheduleActivityTaskCommandAttributes,
24
+ UpsertWorkflowSearchAttributesCommandAttributes, command::Attributes,
25
+ },
26
+ common::v1::ActivityType,
27
+ enums::v1::{CommandType, EventType},
28
+ history::v1::{
29
+ ActivityTaskCompletedEventAttributes, ActivityTaskScheduledEventAttributes,
30
+ ActivityTaskStartedEventAttributes, TimerFiredEventAttributes,
31
+ },
29
32
  },
30
33
  },
31
34
  };
32
35
 
33
36
  use temporalio_common::worker::WorkerTaskTypes;
34
- use temporalio_sdk::{ActivityOptions, WfContext, WorkflowResult};
37
+ use temporalio_macros::{activities, workflow, workflow_methods};
38
+ use temporalio_sdk::{
39
+ ActivityOptions, SyncWorkflowContext, WorkflowContext, WorkflowResult,
40
+ activities::{ActivityContext, ActivityError},
41
+ };
35
42
  use temporalio_sdk_core::test_help::{CoreInternalFlags, MockPollCfg, ResponseType};
36
43
  use tokio::{join, sync::Notify};
37
- use tokio_stream::StreamExt;
38
44
 
39
45
  const MY_PATCH_ID: &str = "integ_test_change_name";
40
46
 
41
- pub(crate) async fn changes_wf(ctx: WfContext) -> WorkflowResult<()> {
42
- if ctx.patched(MY_PATCH_ID) {
43
- ctx.timer(Duration::from_millis(100)).await;
44
- } else {
45
- ctx.timer(Duration::from_millis(200)).await;
46
- }
47
- ctx.timer(Duration::from_millis(200)).await;
48
- if ctx.patched(MY_PATCH_ID) {
49
- ctx.timer(Duration::from_millis(100)).await;
50
- } else {
47
+ #[workflow]
48
+ #[derive(Default)]
49
+ pub(crate) struct ChangesWf;
50
+
51
+ #[workflow_methods]
52
+ impl ChangesWf {
53
+ #[run(name = "writes_change_markers")]
54
+ pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
55
+ if ctx.patched(MY_PATCH_ID) {
56
+ ctx.timer(Duration::from_millis(100)).await;
57
+ } else {
58
+ ctx.timer(Duration::from_millis(200)).await;
59
+ }
51
60
  ctx.timer(Duration::from_millis(200)).await;
61
+ if ctx.patched(MY_PATCH_ID) {
62
+ ctx.timer(Duration::from_millis(100)).await;
63
+ } else {
64
+ ctx.timer(Duration::from_millis(200)).await;
65
+ }
66
+ Ok(())
52
67
  }
53
- Ok(().into())
54
68
  }
55
69
 
56
70
  #[tokio::test]
57
71
  async fn writes_change_markers() {
58
72
  let wf_name = "writes_change_markers";
59
73
  let mut starter = CoreWfStarter::new(wf_name);
60
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
74
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
61
75
  let mut worker = starter.worker().await;
62
- worker.register_wf(wf_name.to_owned(), changes_wf);
76
+ worker.register_workflow::<ChangesWf>();
63
77
 
64
78
  starter.start_with_worker(wf_name, &mut worker).await;
65
79
  worker.run_until_done().await.unwrap();
@@ -67,57 +81,77 @@ async fn writes_change_markers() {
67
81
 
68
82
  /// This one simulates a run as if the worker had the "old" code, then it fails at the end as
69
83
  /// a cheapo way of being re-run, at which point it runs with change checks and the "new" code.
70
- static DID_DIE: AtomicBool = AtomicBool::new(false);
84
+ #[workflow]
85
+ pub(crate) struct NoChangeThenChangeWf {
86
+ did_die: Arc<AtomicBool>,
87
+ }
71
88
 
72
- pub(crate) async fn no_change_then_change_wf(ctx: WfContext) -> WorkflowResult<()> {
73
- if DID_DIE.load(Ordering::Acquire) {
74
- assert!(!ctx.patched(MY_PATCH_ID));
75
- }
76
- ctx.timer(Duration::from_millis(200)).await;
77
- ctx.timer(Duration::from_millis(200)).await;
78
- if DID_DIE.load(Ordering::Acquire) {
79
- assert!(!ctx.patched(MY_PATCH_ID));
80
- }
81
- ctx.timer(Duration::from_millis(200)).await;
89
+ #[workflow_methods(factory_only)]
90
+ impl NoChangeThenChangeWf {
91
+ #[run(name = "can_add_change_markers")]
92
+ pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
93
+ if ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
94
+ assert!(!ctx.patched(MY_PATCH_ID));
95
+ }
96
+ ctx.timer(Duration::from_millis(200)).await;
97
+ ctx.timer(Duration::from_millis(200)).await;
98
+ if ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
99
+ assert!(!ctx.patched(MY_PATCH_ID));
100
+ }
101
+ ctx.timer(Duration::from_millis(200)).await;
82
102
 
83
- if !DID_DIE.load(Ordering::Acquire) {
84
- DID_DIE.store(true, Ordering::Release);
85
- ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
103
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
104
+ ctx.state(|wf| wf.did_die.store(true, Ordering::Release));
105
+ ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
106
+ }
107
+ Ok(())
86
108
  }
87
- Ok(().into())
88
109
  }
89
110
 
90
111
  #[tokio::test]
91
112
  async fn can_add_change_markers() {
92
113
  let wf_name = "can_add_change_markers";
93
114
  let mut starter = CoreWfStarter::new(wf_name);
94
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
115
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
95
116
  let mut worker = starter.worker().await;
96
- worker.register_wf(wf_name.to_owned(), no_change_then_change_wf);
117
+ let did_die = Arc::new(AtomicBool::new(false));
118
+ worker.register_workflow_with_factory(move || NoChangeThenChangeWf {
119
+ did_die: did_die.clone(),
120
+ });
97
121
 
98
122
  starter.start_with_worker(wf_name, &mut worker).await;
99
123
  worker.run_until_done().await.unwrap();
100
124
  }
101
125
 
102
- static DID_DIE_2: AtomicBool = AtomicBool::new(false);
126
+ #[workflow]
127
+ pub(crate) struct ReplayWithChangeMarkerWf {
128
+ did_die: Arc<AtomicBool>,
129
+ }
103
130
 
104
- pub(crate) async fn replay_with_change_marker_wf(ctx: WfContext) -> WorkflowResult<()> {
105
- assert!(ctx.patched(MY_PATCH_ID));
106
- ctx.timer(Duration::from_millis(200)).await;
107
- if !DID_DIE_2.load(Ordering::Acquire) {
108
- DID_DIE_2.store(true, Ordering::Release);
109
- ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
131
+ #[workflow_methods(factory_only)]
132
+ impl ReplayWithChangeMarkerWf {
133
+ #[run(name = "replaying_with_patch_marker")]
134
+ pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
135
+ assert!(ctx.patched(MY_PATCH_ID));
136
+ ctx.timer(Duration::from_millis(200)).await;
137
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
138
+ ctx.state(|wf| wf.did_die.store(true, Ordering::Release));
139
+ ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
140
+ }
141
+ Ok(())
110
142
  }
111
- Ok(().into())
112
143
  }
113
144
 
114
145
  #[tokio::test]
115
146
  async fn replaying_with_patch_marker() {
116
147
  let wf_name = "replaying_with_patch_marker";
117
148
  let mut starter = CoreWfStarter::new(wf_name);
118
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
149
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
119
150
  let mut worker = starter.worker().await;
120
- worker.register_wf(wf_name.to_owned(), replay_with_change_marker_wf);
151
+ let did_die = Arc::new(AtomicBool::new(false));
152
+ worker.register_workflow_with_factory(move || ReplayWithChangeMarkerWf {
153
+ did_die: did_die.clone(),
154
+ });
121
155
 
122
156
  starter.start_with_worker(wf_name, &mut worker).await;
123
157
  worker.run_until_done().await.unwrap();
@@ -126,98 +160,148 @@ async fn replaying_with_patch_marker() {
126
160
  /// Test that the internal patching mechanism works on the second workflow task when replaying.
127
161
  /// Used as regression test for a bug that detected that we did not look ahead far enough to find
128
162
  /// the next workflow task completion, which the flags are attached to.
163
+ #[workflow]
164
+ struct TimerPatchedTimerWf {
165
+ fail_once: Arc<AtomicBool>,
166
+ }
167
+
168
+ #[workflow_methods(factory_only)]
169
+ impl TimerPatchedTimerWf {
170
+ #[run(name = "timer_patched_timer")]
171
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
172
+ ctx.timer(Duration::from_millis(1)).await;
173
+ if ctx.state(|wf| wf.fail_once.load(Ordering::Acquire)) {
174
+ ctx.state(|wf| wf.fail_once.store(false, Ordering::Release));
175
+ panic!("Enchi is hungry!");
176
+ }
177
+ assert!(ctx.patched(MY_PATCH_ID));
178
+ ctx.timer(Duration::from_millis(1)).await;
179
+ Ok(())
180
+ }
181
+ }
182
+
129
183
  #[tokio::test]
130
184
  async fn patched_on_second_workflow_task_is_deterministic() {
131
185
  let wf_name = "timer_patched_timer";
132
186
  let mut starter = CoreWfStarter::new(wf_name);
133
187
  // Disable caching to force replay from beginning
134
- starter.worker_config.max_cached_workflows = 0_usize;
135
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
188
+ starter.sdk_config.max_cached_workflows = 0_usize;
189
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
136
190
  let mut worker = starter.worker().await;
137
- // Include a task failure as well to make sure that works
138
- static FAIL_ONCE: AtomicBool = AtomicBool::new(true);
139
- worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
140
- ctx.timer(Duration::from_millis(1)).await;
141
- if FAIL_ONCE.load(Ordering::Acquire) {
142
- FAIL_ONCE.store(false, Ordering::Release);
143
- panic!("Enchi is hungry!");
144
- }
145
- assert!(ctx.patched(MY_PATCH_ID));
146
- ctx.timer(Duration::from_millis(1)).await;
147
- Ok(().into())
191
+ let fail_once = Arc::new(AtomicBool::new(true));
192
+ worker.register_workflow_with_factory(move || TimerPatchedTimerWf {
193
+ fail_once: fail_once.clone(),
148
194
  });
149
195
 
150
196
  starter.start_with_worker(wf_name, &mut worker).await;
151
197
  worker.run_until_done().await.unwrap();
152
198
  }
153
199
 
200
+ #[workflow]
201
+ struct RemoveDeprecatedPatchNearOtherPatchWf {
202
+ did_die: Arc<AtomicBool>,
203
+ }
204
+
205
+ #[workflow_methods(factory_only)]
206
+ impl RemoveDeprecatedPatchNearOtherPatchWf {
207
+ #[run(name = "can_add_change_markers")]
208
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
209
+ ctx.timer(Duration::from_millis(200)).await;
210
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
211
+ assert!(ctx.deprecate_patch("getting-deprecated"));
212
+ assert!(ctx.patched("staying"));
213
+ } else {
214
+ assert!(ctx.patched("staying"));
215
+ }
216
+ ctx.timer(Duration::from_millis(200)).await;
217
+
218
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
219
+ ctx.state(|wf| wf.did_die.store(true, Ordering::Release));
220
+ ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
221
+ }
222
+ Ok(())
223
+ }
224
+ }
225
+
154
226
  #[tokio::test]
155
227
  async fn can_remove_deprecated_patch_near_other_patch() {
156
228
  let wf_name = "can_add_change_markers";
157
229
  let mut starter = CoreWfStarter::new(wf_name);
158
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
230
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
159
231
  let mut worker = starter.worker().await;
160
232
  let did_die = Arc::new(AtomicBool::new(false));
161
- worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| {
162
- let did_die = did_die.clone();
163
- async move {
164
- ctx.timer(Duration::from_millis(200)).await;
165
- if !did_die.load(Ordering::Acquire) {
166
- assert!(ctx.deprecate_patch("getting-deprecated"));
167
- assert!(ctx.patched("staying"));
168
- } else {
169
- assert!(ctx.patched("staying"));
170
- }
171
- ctx.timer(Duration::from_millis(200)).await;
172
-
173
- if !did_die.load(Ordering::Acquire) {
174
- did_die.store(true, Ordering::Release);
175
- ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
176
- }
177
- Ok(().into())
178
- }
233
+ worker.register_workflow_with_factory(move || RemoveDeprecatedPatchNearOtherPatchWf {
234
+ did_die: did_die.clone(),
179
235
  });
180
236
 
181
237
  starter.start_with_worker(wf_name, &mut worker).await;
182
238
  worker.run_until_done().await.unwrap();
183
239
  }
184
240
 
241
+ #[workflow]
242
+ struct DeprecatedPatchRemovalWf {
243
+ did_die: Arc<AtomicBool>,
244
+ notify: Arc<Notify>,
245
+ signal_received: bool,
246
+ }
247
+
248
+ #[workflow_methods(factory_only)]
249
+ impl DeprecatedPatchRemovalWf {
250
+ #[run(name = "deprecated_patch_removal")]
251
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
252
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
253
+ assert!(ctx.deprecate_patch("getting-deprecated"));
254
+ }
255
+ ctx.state(|wf| wf.notify.notify_one());
256
+ ctx.wait_condition(|s| s.signal_received).await;
257
+
258
+ ctx.timer(Duration::from_millis(1)).await;
259
+
260
+ if !ctx.state(|wf| wf.did_die.load(Ordering::Acquire)) {
261
+ ctx.state(|wf| wf.did_die.store(true, Ordering::Release));
262
+ ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
263
+ }
264
+ Ok(())
265
+ }
266
+
267
+ #[signal]
268
+ fn handle_sig(&mut self, _ctx: &mut SyncWorkflowContext<Self>) {
269
+ self.signal_received = true;
270
+ }
271
+ }
272
+
185
273
  #[tokio::test]
186
274
  async fn deprecated_patch_removal() {
187
275
  let wf_name = "deprecated_patch_removal";
188
276
  let mut starter = CoreWfStarter::new(wf_name);
189
- starter.worker_config.task_types = WorkerTaskTypes::workflow_only();
277
+ starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
190
278
  let mut worker = starter.worker().await;
191
- let client = starter.get_client().await;
192
279
  let wf_id = starter.get_task_queue().to_string();
193
280
  let did_die = Arc::new(AtomicBool::new(false));
194
281
  let send_sig = Arc::new(Notify::new());
195
- let send_sig_c = send_sig.clone();
196
- worker.register_wf(wf_name, move |ctx: WfContext| {
197
- let did_die = did_die.clone();
198
- let send_sig_c = send_sig_c.clone();
199
- async move {
200
- if !did_die.load(Ordering::Acquire) {
201
- assert!(ctx.deprecate_patch("getting-deprecated"));
202
- }
203
- send_sig_c.notify_one();
204
- ctx.make_signal_channel("sig").next().await;
205
-
206
- ctx.timer(Duration::from_millis(1)).await;
207
-
208
- if !did_die.load(Ordering::Acquire) {
209
- did_die.store(true, Ordering::Release);
210
- ctx.force_task_fail(anyhow::anyhow!("i'm ded"));
211
- }
212
- Ok(().into())
213
- }
282
+ let send_sig_clone = send_sig.clone();
283
+ worker.register_workflow_with_factory(move || DeprecatedPatchRemovalWf {
284
+ did_die: did_die.clone(),
285
+ notify: send_sig_clone.clone(),
286
+ signal_received: false,
214
287
  });
215
288
 
216
- starter.start_with_worker(wf_name, &mut worker).await;
289
+ let handle = worker
290
+ .submit_workflow(
291
+ DeprecatedPatchRemovalWf::run,
292
+ (),
293
+ WorkflowStartOptions::new(wf_id.clone(), wf_id).build(),
294
+ )
295
+ .await
296
+ .unwrap();
217
297
  let sig_fut = async {
218
298
  send_sig.notified().await;
219
- client
220
- .signal_workflow_execution(wf_id, "".to_string(), "sig".to_string(), None, None)
299
+ handle
300
+ .signal(
301
+ DeprecatedPatchRemovalWf::handle_sig,
302
+ (),
303
+ WorkflowSignalOptions::default(),
304
+ )
221
305
  .await
222
306
  .unwrap()
223
307
  };
@@ -312,47 +396,81 @@ fn patch_marker_single_activity(
312
396
  t
313
397
  }
314
398
 
315
- async fn v1(ctx: &mut WfContext) {
316
- ctx.activity(ActivityOptions {
317
- activity_id: Some("no_change".to_owned()),
318
- ..Default::default()
319
- })
320
- .await;
399
+ struct FakeAct;
400
+ #[activities]
401
+ impl FakeAct {
402
+ #[activity(name = "")]
403
+ fn nameless(_: ActivityContext) -> Result<RawValue, ActivityError> {
404
+ unimplemented!()
405
+ }
321
406
  }
322
407
 
323
- async fn v2(ctx: &mut WfContext) -> bool {
324
- if ctx.patched(MY_PATCH_ID) {
325
- ctx.activity(ActivityOptions {
326
- activity_id: Some("had_change".to_owned()),
327
- ..Default::default()
328
- })
408
+ async fn v1(ctx: &mut WorkflowContext<PatchWf>) {
409
+ let _ = ctx
410
+ .start_activity(
411
+ FakeAct::nameless,
412
+ (),
413
+ ActivityOptions {
414
+ activity_id: Some("no_change".to_owned()),
415
+ ..Default::default()
416
+ },
417
+ )
329
418
  .await;
419
+ }
420
+
421
+ async fn v2(ctx: &mut WorkflowContext<PatchWf>) -> bool {
422
+ if ctx.patched(MY_PATCH_ID) {
423
+ let _ = ctx
424
+ .start_activity(
425
+ FakeAct::nameless,
426
+ (),
427
+ ActivityOptions {
428
+ activity_id: Some("had_change".to_owned()),
429
+ ..Default::default()
430
+ },
431
+ )
432
+ .await;
330
433
  true
331
434
  } else {
332
- ctx.activity(ActivityOptions {
333
- activity_id: Some("no_change".to_owned()),
334
- ..Default::default()
335
- })
336
- .await;
435
+ let _ = ctx
436
+ .start_activity(
437
+ FakeAct::nameless,
438
+ (),
439
+ ActivityOptions {
440
+ activity_id: Some("no_change".to_owned()),
441
+ ..Default::default()
442
+ },
443
+ )
444
+ .await;
337
445
  false
338
446
  }
339
447
  }
340
448
 
341
- async fn v3(ctx: &mut WfContext) {
449
+ async fn v3(ctx: &mut WorkflowContext<PatchWf>) {
342
450
  ctx.deprecate_patch(MY_PATCH_ID);
343
- ctx.activity(ActivityOptions {
344
- activity_id: Some("had_change".to_owned()),
345
- ..Default::default()
346
- })
347
- .await;
451
+ let _ = ctx
452
+ .start_activity(
453
+ FakeAct::nameless,
454
+ (),
455
+ ActivityOptions {
456
+ activity_id: Some("had_change".to_owned()),
457
+ ..Default::default()
458
+ },
459
+ )
460
+ .await;
348
461
  }
349
462
 
350
- async fn v4(ctx: &mut WfContext) {
351
- ctx.activity(ActivityOptions {
352
- activity_id: Some("had_change".to_owned()),
353
- ..Default::default()
354
- })
355
- .await;
463
+ async fn v4(ctx: &mut WorkflowContext<PatchWf>) {
464
+ let _ = ctx
465
+ .start_activity(
466
+ FakeAct::nameless,
467
+ (),
468
+ ActivityOptions {
469
+ activity_id: Some("had_change".to_owned()),
470
+ ..Default::default()
471
+ },
472
+ )
473
+ .await;
356
474
  }
357
475
 
358
476
  fn patch_setup(replaying: bool, marker_type: MarkerType, workflow_version: usize) -> MockPollCfg {
@@ -364,27 +482,32 @@ fn patch_setup(replaying: bool, marker_type: MarkerType, workflow_version: usize
364
482
  }
365
483
  }
366
484
 
367
- macro_rules! patch_wf {
368
- ($workflow_version:ident) => {
369
- move |mut ctx: WfContext| async move {
370
- match $workflow_version {
371
- 1 => {
372
- v1(&mut ctx).await;
373
- }
374
- 2 => {
375
- v2(&mut ctx).await;
376
- }
377
- 3 => {
378
- v3(&mut ctx).await;
379
- }
380
- 4 => {
381
- v4(&mut ctx).await;
382
- }
383
- _ => panic!("Invalid workflow version for test setup"),
485
+ #[workflow]
486
+ struct PatchWf {
487
+ version: usize,
488
+ }
489
+
490
+ #[workflow_methods(factory_only)]
491
+ impl PatchWf {
492
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
493
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
494
+ match ctx.state(|wf| wf.version) {
495
+ 1 => {
496
+ v1(ctx).await;
497
+ }
498
+ 2 => {
499
+ v2(ctx).await;
500
+ }
501
+ 3 => {
502
+ v3(ctx).await;
384
503
  }
385
- Ok(().into())
504
+ 4 => {
505
+ v4(ctx).await;
506
+ }
507
+ _ => panic!("Invalid workflow version for test setup"),
386
508
  }
387
- };
509
+ Ok(())
510
+ }
388
511
  }
389
512
 
390
513
  #[rstest]
@@ -436,7 +559,9 @@ async fn v1_and_v4_changes(
436
559
 
437
560
  let mut worker = build_fake_sdk(mock_cfg);
438
561
  worker.set_worker_interceptor(aai);
439
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, patch_wf!(wf_version));
562
+ worker.register_workflow_with_factory(move || PatchWf {
563
+ version: wf_version,
564
+ });
440
565
  worker.run().await.unwrap();
441
566
  }
442
567
 
@@ -541,10 +666,39 @@ async fn v2_and_v3_changes(
541
666
 
542
667
  let mut worker = build_fake_sdk(mock_cfg);
543
668
  worker.set_worker_interceptor(aai);
544
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, patch_wf!(wf_version));
669
+ worker.register_workflow_with_factory(move || PatchWf {
670
+ version: wf_version,
671
+ });
545
672
  worker.run().await.unwrap();
546
673
  }
547
674
 
675
+ #[workflow]
676
+ #[derive(Default)]
677
+ struct SameChangeMultipleSpotsWf;
678
+
679
+ #[workflow_methods]
680
+ impl SameChangeMultipleSpotsWf {
681
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
682
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
683
+ if ctx.patched(MY_PATCH_ID) {
684
+ let _ = ctx
685
+ .start_activity(FakeAct::nameless, (), ActivityOptions::default())
686
+ .await;
687
+ } else {
688
+ ctx.timer(ONE_SECOND).await;
689
+ }
690
+ ctx.timer(ONE_SECOND).await;
691
+ if ctx.patched(MY_PATCH_ID) {
692
+ let _ = ctx
693
+ .start_activity(FakeAct::nameless, (), ActivityOptions::default())
694
+ .await;
695
+ } else {
696
+ ctx.timer(ONE_SECOND).await;
697
+ }
698
+ Ok(())
699
+ }
700
+ }
701
+
548
702
  #[rstest]
549
703
  #[case::has_change_replay(true, true)]
550
704
  #[case::no_change_replay(false, true)]
@@ -634,26 +788,30 @@ async fn same_change_multiple_spots(#[case] have_marker_in_hist: bool, #[case] r
634
788
  MockPollCfg::from_hist_builder(t)
635
789
  };
636
790
 
637
- // Errors would appear as nondeterminism problems, so just run it.
638
791
  let mut worker = build_fake_sdk(mock_cfg);
639
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
640
- if ctx.patched(MY_PATCH_ID) {
641
- ctx.activity(ActivityOptions::default()).await;
642
- } else {
643
- ctx.timer(ONE_SECOND).await;
644
- }
645
- ctx.timer(ONE_SECOND).await;
646
- if ctx.patched(MY_PATCH_ID) {
647
- ctx.activity(ActivityOptions::default()).await;
648
- } else {
649
- ctx.timer(ONE_SECOND).await;
650
- }
651
- Ok(().into())
652
- });
792
+ worker.register_workflow::<SameChangeMultipleSpotsWf>();
653
793
  worker.run().await.unwrap();
654
794
  }
655
795
 
656
796
  const SIZE_OVERFLOW_PATCH_AMOUNT: usize = 180;
797
+
798
+ #[workflow]
799
+ struct ManyPatchesWf {
800
+ num_patches: usize,
801
+ }
802
+
803
+ #[workflow_methods(factory_only)]
804
+ impl ManyPatchesWf {
805
+ #[run(name = DEFAULT_WORKFLOW_TYPE)]
806
+ async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
807
+ for i in 1..=ctx.state(|wf| wf.num_patches) {
808
+ let _dontcare = ctx.patched(&format!("patch-{i}"));
809
+ ctx.timer(ONE_SECOND).await;
810
+ }
811
+ Ok(())
812
+ }
813
+ }
814
+
657
815
  #[rstest]
658
816
  #[case::happy_path(50)]
659
817
  // We start exceeding the 2k size limit at 180 patches with this format
@@ -713,12 +871,6 @@ async fn many_patches_combine_in_search_attrib_update(#[case] num_patches: usize
713
871
  });
714
872
 
715
873
  let mut worker = build_fake_sdk(mock_cfg);
716
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
717
- for i in 1..=num_patches {
718
- let _dontcare = ctx.patched(&format!("patch-{i}"));
719
- ctx.timer(ONE_SECOND).await;
720
- }
721
- Ok(().into())
722
- });
874
+ worker.register_workflow_with_factory(move || ManyPatchesWf { num_patches });
723
875
  worker.run().await.unwrap();
724
876
  }