@temporalio/core-bridge 1.13.1 → 1.14.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 (422) hide show
  1. package/Cargo.lock +350 -436
  2. package/Cargo.toml +14 -13
  3. package/{sdk-core/fsm/rustfsm_procmacro/LICENSE.txt → LICENSE} +5 -5
  4. package/README.md +0 -1
  5. package/bridge-macros/Cargo.toml +16 -0
  6. package/bridge-macros/src/derive_js_function.rs +126 -0
  7. package/bridge-macros/src/derive_tryfromjs.rs +138 -0
  8. package/bridge-macros/src/derive_tryintojs.rs +151 -0
  9. package/bridge-macros/src/lib.rs +42 -0
  10. package/lib/native.d.ts +23 -9
  11. package/package.json +6 -5
  12. package/releases/aarch64-apple-darwin/index.node +0 -0
  13. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  14. package/releases/x86_64-apple-darwin/index.node +0 -0
  15. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  16. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  17. package/sdk-core/.cargo/config.toml +78 -12
  18. package/sdk-core/.clippy.toml +1 -0
  19. package/sdk-core/.github/workflows/heavy.yml +2 -0
  20. package/sdk-core/.github/workflows/per-pr.yml +90 -21
  21. package/sdk-core/AGENTS.md +17 -19
  22. package/sdk-core/ARCHITECTURE.md +44 -48
  23. package/sdk-core/Cargo.toml +25 -7
  24. package/sdk-core/README.md +16 -15
  25. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  26. package/sdk-core/arch_docs/diagrams/deps.svg +102 -0
  27. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  28. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  29. package/sdk-core/{client → crates/client}/Cargo.toml +15 -16
  30. package/sdk-core/{client → crates/client}/src/callback_based.rs +1 -2
  31. package/sdk-core/{client → crates/client}/src/lib.rs +594 -457
  32. package/sdk-core/{client → crates/client}/src/metrics.rs +32 -8
  33. package/sdk-core/crates/client/src/proxy.rs +209 -0
  34. package/sdk-core/{client → crates/client}/src/raw.rs +648 -328
  35. package/sdk-core/crates/client/src/replaceable.rs +253 -0
  36. package/sdk-core/crates/client/src/request_extensions.rs +40 -0
  37. package/sdk-core/{client → crates/client}/src/retry.rs +32 -22
  38. package/sdk-core/crates/client/src/worker/mod.rs +1468 -0
  39. package/sdk-core/{client → crates/client}/src/workflow_handle/mod.rs +24 -21
  40. package/sdk-core/{core-api → crates/common}/Cargo.toml +21 -12
  41. package/sdk-core/{sdk-core-protos → crates/common}/build.rs +10 -23
  42. package/sdk-core/crates/common/protos/api_cloud_upstream/VERSION +1 -0
  43. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/account/v1/message.proto +18 -0
  44. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +38 -11
  45. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +21 -4
  46. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +6 -6
  47. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/sink/v1/message.proto +22 -0
  48. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/create-release.yml +13 -0
  49. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/openapi/openapiv2.json +254 -5
  50. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  51. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  52. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  53. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  54. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  55. package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  56. package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  57. package/sdk-core/{core-api → crates/common}/src/envconfig.rs +155 -56
  58. package/sdk-core/{core-api → crates/common}/src/errors.rs +8 -1
  59. package/sdk-core/{fsm/rustfsm_trait/src/lib.rs → crates/common/src/fsm_trait.rs} +1 -27
  60. package/sdk-core/{core-api → crates/common}/src/lib.rs +92 -9
  61. package/sdk-core/{test-utils/src → crates/common/src/protos}/canned_histories.rs +5 -5
  62. package/sdk-core/{sdk-core-protos/src → crates/common/src/protos}/history_builder.rs +3 -3
  63. package/sdk-core/{sdk-core-protos/src → crates/common/src/protos}/history_info.rs +2 -2
  64. package/sdk-core/{sdk-core-protos/src/lib.rs → crates/common/src/protos/mod.rs} +43 -26
  65. package/sdk-core/crates/common/src/protos/test_utils.rs +89 -0
  66. package/sdk-core/{sdk-core-protos/src → crates/common/src/protos}/utilities.rs +14 -5
  67. package/sdk-core/{core-api → crates/common}/src/telemetry/metrics.rs +449 -51
  68. package/sdk-core/{core-api → crates/common}/src/telemetry.rs +16 -1
  69. package/sdk-core/{core-api → crates/common}/src/worker.rs +112 -18
  70. package/sdk-core/crates/common/tests/worker_task_types_test.rs +129 -0
  71. package/sdk-core/crates/macros/Cargo.toml +23 -0
  72. package/sdk-core/{fsm/rustfsm_procmacro → crates/macros}/src/lib.rs +12 -12
  73. package/sdk-core/{sdk → crates/sdk}/Cargo.toml +18 -12
  74. package/sdk-core/{sdk → crates/sdk}/src/activity_context.rs +9 -7
  75. package/sdk-core/{sdk → crates/sdk}/src/app_data.rs +1 -1
  76. package/sdk-core/{sdk → crates/sdk}/src/interceptors.rs +2 -5
  77. package/sdk-core/{sdk → crates/sdk}/src/lib.rs +43 -42
  78. package/sdk-core/{sdk → crates/sdk}/src/workflow_context/options.rs +12 -3
  79. package/sdk-core/{sdk → crates/sdk}/src/workflow_context.rs +21 -19
  80. package/sdk-core/{sdk → crates/sdk}/src/workflow_future.rs +2 -2
  81. package/sdk-core/crates/sdk-core/Cargo.toml +222 -0
  82. package/sdk-core/{core/benches/workflow_replay.rs → crates/sdk-core/benches/workflow_replay_bench.rs} +15 -10
  83. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +32 -0
  84. package/sdk-core/crates/sdk-core/machine_coverage/CancelExternalMachine_Coverage.puml +9 -0
  85. package/sdk-core/crates/sdk-core/machine_coverage/CancelWorkflowMachine_Coverage.puml +6 -0
  86. package/sdk-core/crates/sdk-core/machine_coverage/ChildWorkflowMachine_Coverage.puml +27 -0
  87. package/sdk-core/crates/sdk-core/machine_coverage/CompleteWorkflowMachine_Coverage.puml +6 -0
  88. package/sdk-core/crates/sdk-core/machine_coverage/ContinueAsNewWorkflowMachine_Coverage.puml +6 -0
  89. package/sdk-core/crates/sdk-core/machine_coverage/FailWorkflowMachine_Coverage.puml +6 -0
  90. package/sdk-core/crates/sdk-core/machine_coverage/LocalActivityMachine_Coverage.puml +23 -0
  91. package/sdk-core/crates/sdk-core/machine_coverage/ModifyWorkflowPropertiesMachine_Coverage.puml +5 -0
  92. package/sdk-core/crates/sdk-core/machine_coverage/PatchMachine_Coverage.puml +8 -0
  93. package/sdk-core/crates/sdk-core/machine_coverage/SignalExternalMachine_Coverage.puml +12 -0
  94. package/sdk-core/crates/sdk-core/machine_coverage/TimerMachine_Coverage.puml +13 -0
  95. package/sdk-core/crates/sdk-core/machine_coverage/UpdateMachine_Coverage.puml +19 -0
  96. package/sdk-core/crates/sdk-core/machine_coverage/UpsertSearchAttributesMachine_Coverage.puml +5 -0
  97. package/sdk-core/crates/sdk-core/machine_coverage/WorkflowTaskMachine_Coverage.puml +11 -0
  98. package/sdk-core/{core → crates/sdk-core}/src/abstractions.rs +62 -6
  99. package/sdk-core/crates/sdk-core/src/antithesis.rs +60 -0
  100. package/sdk-core/{core → crates/sdk-core}/src/core_tests/activity_tasks.rs +85 -250
  101. package/sdk-core/{core → crates/sdk-core}/src/core_tests/mod.rs +13 -16
  102. package/sdk-core/{core → crates/sdk-core}/src/core_tests/queries.rs +25 -24
  103. package/sdk-core/{core → crates/sdk-core}/src/core_tests/replay_flag.rs +11 -68
  104. package/sdk-core/{core → crates/sdk-core}/src/core_tests/updates.rs +21 -20
  105. package/sdk-core/{core → crates/sdk-core}/src/core_tests/workers.rs +242 -16
  106. package/sdk-core/{core → crates/sdk-core}/src/core_tests/workflow_cancels.rs +10 -7
  107. package/sdk-core/{core → crates/sdk-core}/src/core_tests/workflow_tasks.rs +150 -326
  108. package/sdk-core/{core → crates/sdk-core}/src/debug_client.rs +1 -1
  109. package/sdk-core/{core → crates/sdk-core}/src/ephemeral_server/mod.rs +18 -6
  110. package/sdk-core/{test-utils → crates/sdk-core}/src/histfetch.rs +9 -4
  111. package/sdk-core/{core → crates/sdk-core}/src/internal_flags.rs +15 -4
  112. package/sdk-core/{core → crates/sdk-core}/src/lib.rs +128 -72
  113. package/sdk-core/{core → crates/sdk-core}/src/pollers/mod.rs +13 -11
  114. package/sdk-core/{core → crates/sdk-core}/src/pollers/poll_buffer.rs +53 -18
  115. package/sdk-core/{core → crates/sdk-core}/src/protosext/mod.rs +14 -6
  116. package/sdk-core/{core → crates/sdk-core}/src/protosext/protocol_messages.rs +5 -12
  117. package/sdk-core/{core → crates/sdk-core}/src/replay/mod.rs +14 -11
  118. package/sdk-core/crates/sdk-core/src/retry_logic.rs +390 -0
  119. package/sdk-core/{core → crates/sdk-core}/src/telemetry/log_export.rs +2 -2
  120. package/sdk-core/{core → crates/sdk-core}/src/telemetry/metrics.rs +80 -33
  121. package/sdk-core/{core → crates/sdk-core}/src/telemetry/mod.rs +12 -6
  122. package/sdk-core/{core → crates/sdk-core}/src/telemetry/otel.rs +1 -1
  123. package/sdk-core/{core → crates/sdk-core}/src/telemetry/prometheus_meter.rs +14 -14
  124. package/sdk-core/{core → crates/sdk-core}/src/telemetry/prometheus_server.rs +2 -2
  125. package/sdk-core/{core/src/test_help/mod.rs → crates/sdk-core/src/test_help/integ_helpers.rs} +284 -329
  126. package/sdk-core/crates/sdk-core/src/test_help/mod.rs +13 -0
  127. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +220 -0
  128. package/sdk-core/{core → crates/sdk-core}/src/worker/activities/activity_heartbeat_manager.rs +44 -8
  129. package/sdk-core/{core → crates/sdk-core}/src/worker/activities/local_activities.rs +33 -31
  130. package/sdk-core/{core → crates/sdk-core}/src/worker/activities.rs +31 -15
  131. package/sdk-core/{core → crates/sdk-core}/src/worker/client/mocks.rs +28 -15
  132. package/sdk-core/{core → crates/sdk-core}/src/worker/client.rs +275 -145
  133. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +246 -0
  134. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1462 -0
  135. package/sdk-core/{core → crates/sdk-core}/src/worker/nexus.rs +24 -12
  136. package/sdk-core/{core → crates/sdk-core}/src/worker/slot_provider.rs +18 -10
  137. package/sdk-core/{core → crates/sdk-core}/src/worker/tuner/fixed_size.rs +5 -1
  138. package/sdk-core/{core → crates/sdk-core}/src/worker/tuner/resource_based.rs +453 -57
  139. package/sdk-core/{core → crates/sdk-core}/src/worker/tuner.rs +179 -3
  140. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/driven_workflow.rs +1 -1
  141. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/history_update.rs +5 -267
  142. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/activity_state_machine.rs +147 -90
  143. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/cancel_external_state_machine.rs +8 -91
  144. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/cancel_nexus_op_state_machine.rs +14 -12
  145. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +97 -0
  146. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/child_workflow_state_machine.rs +32 -229
  147. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -8
  148. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -50
  149. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/fail_workflow_state_machine.rs +6 -7
  150. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/local_activity_state_machine.rs +39 -584
  151. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/mod.rs +22 -17
  152. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -74
  153. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/nexus_operation_state_machine.rs +118 -21
  154. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/patch_state_machine.rs +273 -0
  155. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/signal_external_state_machine.rs +9 -151
  156. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/timer_state_machine.rs +27 -132
  157. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/transition_coverage.rs +1 -2
  158. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/update_state_machine.rs +19 -13
  159. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +25 -80
  160. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/workflow_machines/local_acts.rs +1 -1
  161. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/workflow_machines.rs +68 -72
  162. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -15
  163. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/managed_run.rs +55 -37
  164. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/mod.rs +171 -61
  165. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/run_cache.rs +10 -7
  166. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/wft_extraction.rs +4 -2
  167. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/wft_poller.rs +15 -4
  168. package/sdk-core/{core → crates/sdk-core}/src/worker/workflow/workflow_stream.rs +38 -19
  169. package/sdk-core/crates/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  170. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +25 -0
  171. package/sdk-core/crates/sdk-core/tests/common/fake_grpc_server.rs +106 -0
  172. package/sdk-core/crates/sdk-core/tests/common/http_proxy.rs +134 -0
  173. package/sdk-core/{test-utils/src/lib.rs → crates/sdk-core/tests/common/mod.rs} +286 -334
  174. package/sdk-core/{test-utils/src → crates/sdk-core/tests/common}/workflows.rs +6 -4
  175. package/sdk-core/crates/sdk-core/tests/fsm_procmacro.rs +6 -0
  176. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/dupe_transitions_fail.rs +1 -3
  177. package/sdk-core/crates/sdk-core/tests/fsm_trybuild/dupe_transitions_fail.stderr +12 -0
  178. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/dynamic_dest_pass.rs +2 -4
  179. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/forgot_name_fail.rs +1 -3
  180. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/forgot_name_fail.stderr +4 -4
  181. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/handler_arg_pass.rs +2 -4
  182. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/handler_pass.rs +2 -4
  183. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/medium_complex_pass.rs +2 -4
  184. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/no_handle_conversions_require_into_fail.rs +2 -4
  185. package/sdk-core/crates/sdk-core/tests/fsm_trybuild/no_handle_conversions_require_into_fail.stderr +15 -0
  186. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/simple_pass.rs +2 -4
  187. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/struct_event_variant_fail.rs +1 -3
  188. package/sdk-core/crates/sdk-core/tests/fsm_trybuild/struct_event_variant_fail.stderr +5 -0
  189. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/tuple_more_item_event_variant_fail.rs +1 -3
  190. package/sdk-core/crates/sdk-core/tests/fsm_trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  191. package/sdk-core/{fsm/rustfsm_procmacro/tests/trybuild → crates/sdk-core/tests/fsm_trybuild}/tuple_zero_item_event_variant_fail.rs +1 -3
  192. package/sdk-core/crates/sdk-core/tests/fsm_trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  193. package/sdk-core/{tests → crates/sdk-core/tests}/global_metric_tests.rs +22 -22
  194. package/sdk-core/{tests → crates/sdk-core/tests/heavy_tests}/fuzzy_workflow.rs +4 -4
  195. package/sdk-core/{tests → crates/sdk-core/tests}/heavy_tests.rs +25 -14
  196. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/activity_functions.rs +1 -1
  197. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/client_tests.rs +115 -123
  198. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/ephemeral_server_tests.rs +19 -15
  199. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/heartbeat_tests.rs +24 -20
  200. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/metrics_tests.rs +241 -67
  201. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  202. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +513 -0
  203. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/queries_tests.rs +13 -11
  204. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/update_tests.rs +47 -29
  205. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/visibility_tests.rs +49 -27
  206. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +1061 -0
  207. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +920 -0
  208. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/worker_versioning_tests.rs +58 -40
  209. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/activities.rs +268 -30
  210. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/appdata_propagation.rs +4 -4
  211. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +155 -0
  212. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +121 -0
  213. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +717 -0
  214. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +109 -0
  215. package/sdk-core/{core/src/core_tests → crates/sdk-core/tests/integ_tests/workflow_tests}/determinism.rs +108 -20
  216. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/eager.rs +10 -5
  217. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +2884 -0
  218. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +119 -0
  219. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/nexus.rs +174 -46
  220. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +740 -0
  221. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/replay.rs +78 -27
  222. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/resets.rs +46 -28
  223. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +294 -0
  224. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/stickyness.rs +9 -8
  225. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +249 -0
  226. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/upsert_search_attrs.rs +72 -7
  227. package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests.rs +97 -33
  228. package/sdk-core/{tests → crates/sdk-core/tests}/main.rs +40 -25
  229. package/sdk-core/{tests → crates/sdk-core/tests}/manual_tests.rs +25 -15
  230. package/sdk-core/{tests → crates/sdk-core/tests}/runner.rs +23 -41
  231. package/sdk-core/{tests → crates/sdk-core/tests}/shared_tests/mod.rs +11 -6
  232. package/sdk-core/{tests → crates/sdk-core/tests}/shared_tests/priority.rs +6 -6
  233. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +59 -0
  234. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/include/temporal-sdk-core-c-bridge.h +215 -44
  235. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/client.rs +515 -214
  236. package/sdk-core/crates/sdk-core-c-bridge/src/envconfig.rs +314 -0
  237. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/lib.rs +2 -1
  238. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/metric.rs +1 -1
  239. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/random.rs +4 -4
  240. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/runtime.rs +42 -28
  241. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/testing.rs +2 -5
  242. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/tests/context.rs +42 -41
  243. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/tests/mod.rs +38 -34
  244. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/tests/utils.rs +10 -11
  245. package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/src/worker.rs +427 -121
  246. package/sdk-core/docker-cgroup-tests.sh +24 -0
  247. package/sdk-core/{docker → etc/docker}/docker-compose-ci.yaml +9 -9
  248. package/sdk-core/{docker → etc/docker}/docker-compose-telem.yaml +11 -11
  249. package/sdk-core/{docker → etc/docker}/docker-compose.yaml +8 -8
  250. package/sdk-core/{integ-with-otel.sh → etc/integ-with-otel.sh} +1 -1
  251. package/sdk-core/etc/regen-depgraph.sh +2 -2
  252. package/src/client.rs +117 -49
  253. package/src/helpers/callbacks.rs +4 -4
  254. package/src/helpers/errors.rs +7 -1
  255. package/src/helpers/handles.rs +1 -0
  256. package/src/helpers/try_from_js.rs +5 -4
  257. package/src/lib.rs +3 -2
  258. package/src/logs.rs +1 -1
  259. package/src/metrics.rs +6 -3
  260. package/src/runtime.rs +41 -24
  261. package/src/testing.rs +3 -3
  262. package/src/worker.rs +77 -44
  263. package/ts/native.ts +26 -9
  264. package/LICENSE.md +0 -23
  265. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  266. package/sdk-core/client/src/proxy.rs +0 -90
  267. package/sdk-core/client/src/worker_registry/mod.rs +0 -266
  268. package/sdk-core/core/Cargo.toml +0 -146
  269. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  270. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  271. package/sdk-core/core/src/retry_logic.rs +0 -224
  272. package/sdk-core/core/src/worker/heartbeat.rs +0 -231
  273. package/sdk-core/core/src/worker/mod.rs +0 -980
  274. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -165
  275. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +0 -801
  276. package/sdk-core/core-c-bridge/Cargo.toml +0 -51
  277. package/sdk-core/etc/deps.svg +0 -162
  278. package/sdk-core/fsm/Cargo.toml +0 -21
  279. package/sdk-core/fsm/README.md +0 -3
  280. package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +0 -27
  281. package/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +0 -8
  282. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +0 -12
  283. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +0 -15
  284. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +0 -5
  285. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +0 -5
  286. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +0 -5
  287. package/sdk-core/fsm/rustfsm_trait/Cargo.toml +0 -14
  288. package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -21
  289. package/sdk-core/fsm/src/lib.rs +0 -2
  290. package/sdk-core/sdk-core-protos/Cargo.toml +0 -37
  291. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +0 -1
  292. package/sdk-core/test-utils/Cargo.toml +0 -38
  293. package/sdk-core/test-utils/src/interceptors.rs +0 -46
  294. package/sdk-core/tests/cloud_tests.rs +0 -23
  295. package/sdk-core/tests/integ_tests/polling_tests.rs +0 -294
  296. package/sdk-core/tests/integ_tests/worker_tests.rs +0 -203
  297. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +0 -74
  298. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +0 -57
  299. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +0 -246
  300. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +0 -65
  301. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +0 -85
  302. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +0 -908
  303. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +0 -51
  304. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +0 -206
  305. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +0 -164
  306. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +0 -123
  307. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/.github/workflows/build.yaml +0 -0
  308. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/.github/workflows/push-to-buf.yml +0 -0
  309. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/CODEOWNERS +0 -0
  310. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/LICENSE +0 -0
  311. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/Makefile +0 -0
  312. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/README.md +0 -0
  313. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/buf.gen.yaml +0 -0
  314. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/buf.lock +0 -0
  315. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/buf.yaml +0 -0
  316. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/connectivityrule/v1/message.proto +0 -0
  317. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +0 -0
  318. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +0 -0
  319. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/nexus/v1/message.proto +0 -0
  320. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +0 -0
  321. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/resource/v1/message.proto +0 -0
  322. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_cloud_upstream/temporal/api/cloud/usage/v1/message.proto +0 -0
  323. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/CODEOWNERS +0 -0
  324. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  325. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/ci.yml +0 -0
  326. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/publish-docs.yml +0 -0
  327. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/push-to-buf.yml +0 -0
  328. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/trigger-api-go-delete-release.yml +0 -0
  329. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/trigger-api-go-publish-release.yml +0 -0
  330. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
  331. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/LICENSE +0 -0
  332. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/Makefile +0 -0
  333. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/README.md +0 -0
  334. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/api-linter.yaml +0 -0
  335. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/buf.gen.yaml +0 -0
  336. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/buf.lock +0 -0
  337. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/buf.yaml +0 -0
  338. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/api/annotations.proto +0 -0
  339. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/api/http.proto +0 -0
  340. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/any.proto +0 -0
  341. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/descriptor.proto +0 -0
  342. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/duration.proto +0 -0
  343. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/empty.proto +0 -0
  344. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/struct.proto +0 -0
  345. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/timestamp.proto +0 -0
  346. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/google/protobuf/wrappers.proto +0 -0
  347. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/openapi/payload_description.txt +0 -0
  348. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/activity/v1/message.proto +0 -0
  349. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/batch/v1/message.proto +0 -0
  350. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/command/v1/message.proto +0 -0
  351. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
  352. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
  353. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/common.proto +0 -0
  354. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/deployment.proto +0 -0
  355. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
  356. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +0 -0
  357. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
  358. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/nexus.proto +0 -0
  359. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/query.proto +0 -0
  360. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/reset.proto +0 -0
  361. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
  362. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
  363. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/update.proto +0 -0
  364. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
  365. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
  366. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/export/v1/message.proto +0 -0
  367. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/failure/v1/message.proto +0 -0
  368. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/filter/v1/message.proto +0 -0
  369. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/history/v1/message.proto +0 -0
  370. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/nexus/v1/message.proto +0 -0
  371. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +0 -0
  372. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -0
  373. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
  374. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/query/v1/message.proto +0 -0
  375. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/replication/v1/message.proto +0 -0
  376. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/rules/v1/message.proto +0 -0
  377. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/schedule/v1/message.proto +0 -0
  378. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +0 -0
  379. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +0 -0
  380. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +0 -0
  381. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/sdk/v1/worker_config.proto +0 -0
  382. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +0 -0
  383. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +0 -0
  384. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/update/v1/message.proto +0 -0
  385. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/version/v1/message.proto +0 -0
  386. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/worker/v1/message.proto +0 -0
  387. /package/sdk-core/{sdk-core-protos → crates/common}/protos/api_upstream/temporal/api/workflow/v1/message.proto +0 -0
  388. /package/sdk-core/{sdk-core-protos → crates/common}/protos/google/rpc/status.proto +0 -0
  389. /package/sdk-core/{sdk-core-protos → crates/common}/protos/grpc/health/v1/health.proto +0 -0
  390. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
  391. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
  392. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
  393. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/common/common.proto +0 -0
  394. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/core_interface.proto +0 -0
  395. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/external_data/external_data.proto +0 -0
  396. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/nexus/nexus.proto +0 -0
  397. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +0 -0
  398. /package/sdk-core/{sdk-core-protos → crates/common}/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
  399. /package/sdk-core/{sdk-core-protos → crates/common}/protos/testsrv_upstream/Makefile +0 -0
  400. /package/sdk-core/{sdk-core-protos → crates/common}/protos/testsrv_upstream/api-linter.yaml +0 -0
  401. /package/sdk-core/{sdk-core-protos → crates/common}/protos/testsrv_upstream/buf.yaml +0 -0
  402. /package/sdk-core/{sdk-core-protos → crates/common}/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
  403. /package/sdk-core/{sdk-core-protos → crates/common}/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
  404. /package/sdk-core/{sdk-core-protos/src → crates/common/src/protos}/constants.rs +0 -0
  405. /package/sdk-core/{sdk-core-protos/src → crates/common/src/protos}/task_token.rs +0 -0
  406. /package/sdk-core/{fsm → crates/macros}/LICENSE.txt +0 -0
  407. /package/sdk-core/{core → crates/sdk-core}/src/abstractions/take_cell.rs +0 -0
  408. /package/sdk-core/{core → crates/sdk-core}/src/worker/slot_supplier.rs +0 -0
  409. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/ends_empty_wft_complete.bin +0 -0
  410. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/evict_while_la_running_no_interference-16_history.bin +0 -0
  411. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/evict_while_la_running_no_interference-23_history.bin +0 -0
  412. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/evict_while_la_running_no_interference-85_history.bin +0 -0
  413. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/fail_wf_task.bin +0 -0
  414. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/long_local_activity_with_update-0_history.bin +0 -0
  415. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/long_local_activity_with_update-1_history.bin +0 -0
  416. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/long_local_activity_with_update-2_history.bin +0 -0
  417. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/long_local_activity_with_update-3_history.bin +0 -0
  418. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/old_change_marker_format.bin +0 -0
  419. /package/sdk-core/{histories → crates/sdk-core/tests/histories}/timer_workflow_history.bin +0 -0
  420. /package/sdk-core/{tests → crates/sdk-core/tests}/integ_tests/workflow_tests/priority.rs +0 -0
  421. /package/sdk-core/{core-c-bridge → crates/sdk-core-c-bridge}/build.rs +0 -0
  422. /package/sdk-core/{cargo-tokio-console.sh → etc/cargo-tokio-console.sh} +0 -0
@@ -1,1442 +0,0 @@
1
- use crate::{
2
- prost_dur,
3
- replay::{DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, default_wes_attribs},
4
- test_help::{
5
- MockPollCfg, ResponseType, WorkerExt, build_mock_pollers, hist_to_poll_resp, mock_sdk,
6
- mock_sdk_cfg, mock_worker, single_hist_mock_sg,
7
- },
8
- worker::{LEGACY_QUERY_ID, client::mocks::mock_worker_client},
9
- };
10
- use anyhow::anyhow;
11
- use crossbeam_queue::SegQueue;
12
- use futures_util::{FutureExt, future::join_all};
13
- use std::{
14
- collections::HashMap,
15
- ops::Sub,
16
- sync::{
17
- Arc,
18
- atomic::{AtomicUsize, Ordering},
19
- },
20
- time::{Duration, Instant, SystemTime},
21
- };
22
- use temporal_client::WorkflowOptions;
23
- use temporal_sdk::{
24
- ActContext, ActivityError, LocalActivityOptions, WfContext, WorkflowFunction, WorkflowResult,
25
- };
26
- use temporal_sdk_core_api::{Worker, errors::PollError};
27
- use temporal_sdk_core_protos::{
28
- DEFAULT_ACTIVITY_TYPE,
29
- coresdk::{
30
- ActivityTaskCompletion, AsJsonPayloadExt,
31
- activity_result::ActivityExecutionResult,
32
- workflow_activation::{WorkflowActivationJob, workflow_activation_job},
33
- workflow_commands::{ActivityCancellationType, ScheduleLocalActivity},
34
- workflow_completion::WorkflowActivationCompletion,
35
- },
36
- temporal::api::{
37
- common::v1::RetryPolicy,
38
- enums::v1::{CommandType, EventType, TimeoutType, WorkflowTaskFailedCause},
39
- failure::v1::{Failure, failure::FailureInfo},
40
- query::v1::WorkflowQuery,
41
- },
42
- };
43
- use temporal_sdk_core_test_utils::{
44
- WorkerTestHelpers, query_ok, schedule_local_activity_cmd, start_timer_cmd,
45
- };
46
- use tokio::{join, select, sync::Barrier};
47
-
48
- async fn echo(_ctx: ActContext, e: String) -> Result<String, ActivityError> {
49
- Ok(e)
50
- }
51
-
52
- /// This test verifies that when replaying we are able to resolve local activities whose data we
53
- /// don't see until after the workflow issues the command
54
- #[rstest::rstest]
55
- #[case::replay(true, true)]
56
- #[case::not_replay(false, true)]
57
- #[case::replay_cache_off(true, false)]
58
- #[case::not_replay_cache_off(false, false)]
59
- #[tokio::test]
60
- async fn local_act_two_wfts_before_marker(#[case] replay: bool, #[case] cached: bool) {
61
- let mut t = TestHistoryBuilder::default();
62
- t.add_by_type(EventType::WorkflowExecutionStarted);
63
- t.add_full_wf_task();
64
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
65
- t.add_full_wf_task();
66
- t.add_local_activity_result_marker(1, "1", b"echo".into());
67
- t.add_timer_fired(timer_started_event_id, "1".to_string());
68
- t.add_full_wf_task();
69
- t.add_workflow_execution_completed();
70
-
71
- let wf_id = "fakeid";
72
- let mock = mock_worker_client();
73
- let resps = if replay {
74
- vec![ResponseType::AllHistory]
75
- } else {
76
- vec![1.into(), 2.into(), ResponseType::AllHistory]
77
- };
78
- let mh = MockPollCfg::from_resp_batches(wf_id, t, resps, mock);
79
- let mut worker = mock_sdk_cfg(mh, |cfg| {
80
- if cached {
81
- cfg.max_cached_workflows = 1;
82
- }
83
- });
84
-
85
- worker.register_wf(
86
- DEFAULT_WORKFLOW_TYPE.to_owned(),
87
- |ctx: WfContext| async move {
88
- let la = ctx.local_activity(LocalActivityOptions {
89
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
90
- input: "hi".as_json_payload().expect("serializes fine"),
91
- ..Default::default()
92
- });
93
- ctx.timer(Duration::from_secs(1)).await;
94
- la.await;
95
- Ok(().into())
96
- },
97
- );
98
- worker.register_activity(DEFAULT_ACTIVITY_TYPE, echo);
99
- worker
100
- .submit_wf(
101
- wf_id.to_owned(),
102
- DEFAULT_WORKFLOW_TYPE.to_owned(),
103
- vec![],
104
- WorkflowOptions::default(),
105
- )
106
- .await
107
- .unwrap();
108
- worker.run_until_done().await.unwrap();
109
- }
110
-
111
- pub(crate) async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
112
- let las: Vec<_> = (1..=50)
113
- .map(|i| {
114
- ctx.local_activity(LocalActivityOptions {
115
- activity_type: "echo".to_string(),
116
- input: format!("Hi {i}")
117
- .as_json_payload()
118
- .expect("serializes fine"),
119
- ..Default::default()
120
- })
121
- })
122
- .collect();
123
- ctx.timer(Duration::from_secs(1)).await;
124
- join_all(las).await;
125
- Ok(().into())
126
- }
127
-
128
- #[tokio::test]
129
- async fn local_act_many_concurrent() {
130
- let mut t = TestHistoryBuilder::default();
131
- t.add_by_type(EventType::WorkflowExecutionStarted);
132
- t.add_full_wf_task();
133
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
134
- t.add_full_wf_task();
135
- for i in 1..=50 {
136
- t.add_local_activity_result_marker(i, &i.to_string(), b"echo".into());
137
- }
138
- t.add_timer_fired(timer_started_event_id, "1".to_string());
139
- t.add_full_wf_task();
140
- t.add_workflow_execution_completed();
141
-
142
- let wf_id = "fakeid";
143
- let mock = mock_worker_client();
144
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 3], mock);
145
- let mut worker = mock_sdk(mh);
146
-
147
- worker.register_wf(DEFAULT_WORKFLOW_TYPE.to_owned(), local_act_fanout_wf);
148
- worker.register_activity("echo", echo);
149
- worker
150
- .submit_wf(
151
- wf_id.to_owned(),
152
- DEFAULT_WORKFLOW_TYPE.to_owned(),
153
- vec![],
154
- WorkflowOptions::default(),
155
- )
156
- .await
157
- .unwrap();
158
- worker.run_until_done().await.unwrap();
159
- }
160
-
161
- /// Verifies that local activities which take more than a workflow task timeout will cause
162
- /// us to issue additional (empty) WFT completions with the force flag on, thus preventing timeout
163
- /// of WFT while the local activity continues to execute.
164
- ///
165
- /// The test with shutdown verifies if we call shutdown while the local activity is running that
166
- /// shutdown does not complete until it's finished.
167
- #[rstest::rstest]
168
- #[case::with_shutdown(true)]
169
- #[case::normal_complete(false)]
170
- #[tokio::test]
171
- async fn local_act_heartbeat(#[case] shutdown_middle: bool) {
172
- let mut t = TestHistoryBuilder::default();
173
- let wft_timeout = Duration::from_millis(200);
174
- t.add_wfe_started_with_wft_timeout(wft_timeout);
175
- t.add_full_wf_task();
176
- // Task created by WFT heartbeat
177
- t.add_full_wf_task();
178
- t.add_workflow_task_scheduled_and_started();
179
-
180
- let wf_id = "fakeid";
181
- let mock = mock_worker_client();
182
- let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 2, 2], mock);
183
- mh.enforce_correct_number_of_polls = false;
184
- let mut worker = mock_sdk_cfg(mh, |wc| {
185
- wc.max_cached_workflows = 1;
186
- wc.max_outstanding_workflow_tasks = Some(1);
187
- });
188
- let core = worker.core_worker.clone();
189
-
190
- let shutdown_barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
191
-
192
- worker.register_wf(
193
- DEFAULT_WORKFLOW_TYPE.to_owned(),
194
- |ctx: WfContext| async move {
195
- ctx.local_activity(LocalActivityOptions {
196
- activity_type: "echo".to_string(),
197
- input: "hi".as_json_payload().expect("serializes fine"),
198
- ..Default::default()
199
- })
200
- .await;
201
- Ok(().into())
202
- },
203
- );
204
- worker.register_activity("echo", move |_ctx: ActContext, str: String| async move {
205
- if shutdown_middle {
206
- shutdown_barr.wait().await;
207
- }
208
- // Take slightly more than two workflow tasks
209
- tokio::time::sleep(wft_timeout.mul_f32(2.2)).await;
210
- Ok(str)
211
- });
212
- worker
213
- .submit_wf(
214
- wf_id.to_owned(),
215
- DEFAULT_WORKFLOW_TYPE.to_owned(),
216
- vec![],
217
- WorkflowOptions::default(),
218
- )
219
- .await
220
- .unwrap();
221
- let (_, runres) = tokio::join!(
222
- async {
223
- if shutdown_middle {
224
- shutdown_barr.wait().await;
225
- core.shutdown().await;
226
- }
227
- },
228
- worker.run_until_done()
229
- );
230
- runres.unwrap();
231
- }
232
-
233
- #[rstest::rstest]
234
- #[case::retry_then_pass(true)]
235
- #[case::retry_until_fail(false)]
236
- #[tokio::test]
237
- async fn local_act_fail_and_retry(#[case] eventually_pass: bool) {
238
- let mut t = TestHistoryBuilder::default();
239
- t.add_by_type(EventType::WorkflowExecutionStarted);
240
- t.add_workflow_task_scheduled_and_started();
241
-
242
- let wf_id = "fakeid";
243
- let mock = mock_worker_client();
244
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [1], mock);
245
- let mut worker = mock_sdk(mh);
246
-
247
- worker.register_wf(
248
- DEFAULT_WORKFLOW_TYPE.to_owned(),
249
- move |ctx: WfContext| async move {
250
- let la_res = ctx
251
- .local_activity(LocalActivityOptions {
252
- activity_type: "echo".to_string(),
253
- input: "hi".as_json_payload().expect("serializes fine"),
254
- retry_policy: RetryPolicy {
255
- initial_interval: Some(prost_dur!(from_millis(50))),
256
- backoff_coefficient: 1.2,
257
- maximum_interval: None,
258
- maximum_attempts: 5,
259
- non_retryable_error_types: vec![],
260
- },
261
- ..Default::default()
262
- })
263
- .await;
264
- if eventually_pass {
265
- assert!(la_res.completed_ok())
266
- } else {
267
- assert!(la_res.failed())
268
- }
269
- Ok(().into())
270
- },
271
- );
272
- let attempts: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
273
- worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
274
- // Succeed on 3rd attempt (which is ==2 since fetch_add returns prev val)
275
- if 2 == attempts.fetch_add(1, Ordering::Relaxed) && eventually_pass {
276
- Ok(())
277
- } else {
278
- Err(anyhow!("Oh no I failed!").into())
279
- }
280
- });
281
- worker
282
- .submit_wf(
283
- wf_id.to_owned(),
284
- DEFAULT_WORKFLOW_TYPE.to_owned(),
285
- vec![],
286
- WorkflowOptions::default(),
287
- )
288
- .await
289
- .unwrap();
290
- worker.run_until_done().await.unwrap();
291
- let expected_attempts = if eventually_pass { 3 } else { 5 };
292
- assert_eq!(expected_attempts, attempts.load(Ordering::Relaxed));
293
- }
294
-
295
- #[tokio::test]
296
- async fn local_act_retry_long_backoff_uses_timer() {
297
- let mut t = TestHistoryBuilder::default();
298
- t.add_by_type(EventType::WorkflowExecutionStarted);
299
- t.add_full_wf_task();
300
- t.add_local_activity_fail_marker(
301
- 1,
302
- "1",
303
- Failure::application_failure("la failed".to_string(), false),
304
- );
305
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
306
- t.add_timer_fired(timer_started_event_id, "1".to_string());
307
- t.add_full_wf_task();
308
- t.add_local_activity_fail_marker(
309
- 2,
310
- "2",
311
- Failure::application_failure("la failed".to_string(), false),
312
- );
313
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
314
- t.add_timer_fired(timer_started_event_id, "2".to_string());
315
- t.add_full_wf_task();
316
- t.add_workflow_execution_completed();
317
-
318
- let wf_id = "fakeid";
319
- let mock = mock_worker_client();
320
- let mh = MockPollCfg::from_resp_batches(
321
- wf_id,
322
- t,
323
- [1.into(), 2.into(), ResponseType::AllHistory],
324
- mock,
325
- );
326
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
327
-
328
- worker.register_wf(
329
- DEFAULT_WORKFLOW_TYPE.to_owned(),
330
- |ctx: WfContext| async move {
331
- let la_res = ctx
332
- .local_activity(LocalActivityOptions {
333
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
334
- input: "hi".as_json_payload().expect("serializes fine"),
335
- retry_policy: RetryPolicy {
336
- initial_interval: Some(prost_dur!(from_millis(65))),
337
- // This will make the second backoff 65 seconds, plenty to use timer
338
- backoff_coefficient: 1_000.,
339
- maximum_interval: Some(prost_dur!(from_secs(600))),
340
- maximum_attempts: 3,
341
- non_retryable_error_types: vec![],
342
- },
343
- ..Default::default()
344
- })
345
- .await;
346
- assert!(la_res.failed());
347
- // Extra timer just to have an extra workflow task which we can return full history for
348
- ctx.timer(Duration::from_secs(1)).await;
349
- Ok(().into())
350
- },
351
- );
352
- worker.register_activity(
353
- DEFAULT_ACTIVITY_TYPE,
354
- move |_ctx: ActContext, _: String| async move {
355
- Result::<(), _>::Err(anyhow!("Oh no I failed!").into())
356
- },
357
- );
358
- worker
359
- .submit_wf(
360
- wf_id.to_owned(),
361
- DEFAULT_WORKFLOW_TYPE.to_owned(),
362
- vec![],
363
- WorkflowOptions::default(),
364
- )
365
- .await
366
- .unwrap();
367
- worker.run_until_done().await.unwrap();
368
- }
369
-
370
- #[tokio::test]
371
- async fn local_act_null_result() {
372
- let mut t = TestHistoryBuilder::default();
373
- t.add_by_type(EventType::WorkflowExecutionStarted);
374
- t.add_full_wf_task();
375
- t.add_local_activity_marker(1, "1", None, None, |_| {});
376
- t.add_workflow_execution_completed();
377
-
378
- let wf_id = "fakeid";
379
- let mock = mock_worker_client();
380
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
381
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
382
-
383
- worker.register_wf(
384
- DEFAULT_WORKFLOW_TYPE.to_owned(),
385
- |ctx: WfContext| async move {
386
- ctx.local_activity(LocalActivityOptions {
387
- activity_type: "nullres".to_string(),
388
- input: "hi".as_json_payload().expect("serializes fine"),
389
- ..Default::default()
390
- })
391
- .await;
392
- Ok(().into())
393
- },
394
- );
395
- worker.register_activity("nullres", |_ctx: ActContext, _: String| async { Ok(()) });
396
- worker
397
- .submit_wf(
398
- wf_id.to_owned(),
399
- DEFAULT_WORKFLOW_TYPE.to_owned(),
400
- vec![],
401
- WorkflowOptions::default(),
402
- )
403
- .await
404
- .unwrap();
405
- worker.run_until_done().await.unwrap();
406
- }
407
-
408
- #[tokio::test]
409
- async fn local_act_command_immediately_follows_la_marker() {
410
- // This repro only works both when cache is off, and there is at least one heartbeat wft
411
- // before the marker & next command are recorded.
412
- let mut t = TestHistoryBuilder::default();
413
- t.add_by_type(EventType::WorkflowExecutionStarted);
414
- t.add_full_wf_task();
415
- t.add_full_wf_task();
416
- t.add_local_activity_result_marker(1, "1", "done".into());
417
- t.add_by_type(EventType::TimerStarted);
418
- t.add_full_wf_task();
419
-
420
- let wf_id = "fakeid";
421
- let mock = mock_worker_client();
422
- // Bug only repros when seeing history up to third wft
423
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [3], mock);
424
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 0);
425
-
426
- worker.register_wf(
427
- DEFAULT_WORKFLOW_TYPE.to_owned(),
428
- |ctx: WfContext| async move {
429
- ctx.local_activity(LocalActivityOptions {
430
- activity_type: "nullres".to_string(),
431
- input: "hi".as_json_payload().expect("serializes fine"),
432
- ..Default::default()
433
- })
434
- .await;
435
- ctx.timer(Duration::from_secs(1)).await;
436
- Ok(().into())
437
- },
438
- );
439
- worker.register_activity("nullres", |_ctx: ActContext, _: String| async { Ok(()) });
440
- worker
441
- .submit_wf(
442
- wf_id.to_owned(),
443
- DEFAULT_WORKFLOW_TYPE.to_owned(),
444
- vec![],
445
- WorkflowOptions::default(),
446
- )
447
- .await
448
- .unwrap();
449
- worker.run_until_done().await.unwrap();
450
- }
451
-
452
- #[tokio::test]
453
- async fn query_during_wft_heartbeat_doesnt_accidentally_fail_to_continue_heartbeat() {
454
- let wfid = "fake_wf_id";
455
- let mut t = TestHistoryBuilder::default();
456
- t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
457
- t.add_full_wf_task();
458
- // get query here
459
- t.add_full_wf_task();
460
- t.add_local_activity_result_marker(1, "1", "done".into());
461
- t.add_workflow_execution_completed();
462
-
463
- let query_with_hist_task = {
464
- let mut pr = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1));
465
- pr.queries = HashMap::new();
466
- pr.queries.insert(
467
- "the-query".to_string(),
468
- WorkflowQuery {
469
- query_type: "query-type".to_string(),
470
- query_args: Some(b"hi".into()),
471
- header: None,
472
- },
473
- );
474
- pr
475
- };
476
- let after_la_resolved = Arc::new(Barrier::new(2));
477
- let poll_barr = after_la_resolved.clone();
478
- let tasks = [
479
- query_with_hist_task,
480
- hist_to_poll_resp(
481
- &t,
482
- wfid,
483
- ResponseType::UntilResolved(
484
- async move {
485
- poll_barr.wait().await;
486
- }
487
- .boxed(),
488
- 3,
489
- ),
490
- ),
491
- ];
492
- let mock = mock_worker_client();
493
- let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
494
- mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
495
- let core = mock_worker(mock);
496
-
497
- let barrier = Barrier::new(2);
498
-
499
- let wf_fut = async {
500
- let task = core.poll_workflow_activation().await.unwrap();
501
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
502
- task.run_id,
503
- schedule_local_activity_cmd(
504
- 1,
505
- "1",
506
- ActivityCancellationType::TryCancel,
507
- Duration::from_secs(60),
508
- ),
509
- ))
510
- .await
511
- .unwrap();
512
- let task = core.poll_workflow_activation().await.unwrap();
513
- // Get query, and complete it
514
- let query = assert_matches!(
515
- task.jobs.as_slice(),
516
- [WorkflowActivationJob {
517
- variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
518
- }] => q
519
- );
520
- // Now complete the LA
521
- barrier.wait().await;
522
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
523
- task.run_id,
524
- query_ok(&query.query_id, "whatev"),
525
- ))
526
- .await
527
- .unwrap();
528
- // Activation with it resolving:
529
- let task = core.poll_workflow_activation().await.unwrap();
530
- assert_matches!(
531
- task.jobs.as_slice(),
532
- [WorkflowActivationJob {
533
- variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
534
- }]
535
- );
536
- core.complete_execution(&task.run_id).await;
537
- };
538
- let act_fut = async {
539
- let act_task = core.poll_activity_task().await.unwrap();
540
- barrier.wait().await;
541
- core.complete_activity_task(ActivityTaskCompletion {
542
- task_token: act_task.task_token,
543
- result: Some(ActivityExecutionResult::ok(vec![1].into())),
544
- })
545
- .await
546
- .unwrap();
547
- after_la_resolved.wait().await;
548
- };
549
-
550
- tokio::join!(wf_fut, act_fut);
551
- }
552
-
553
- #[rstest::rstest]
554
- #[case::impossible_query_in_task(true)]
555
- #[case::real_history(false)]
556
- #[tokio::test]
557
- async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_query_in_task: bool) {
558
- // Ensures we do not send an activation with a legacy query and any other work, which should
559
- // never happen, but there was an issue where an LA resolving could trigger that.
560
- let wfid = "fake_wf_id";
561
- let mut t = TestHistoryBuilder::default();
562
- t.add(default_wes_attribs());
563
- // Since we don't send queries with start workflow, need one workflow task of something else
564
- // b/c we want to get an activation with a job and a nonlegacy query
565
- t.add_full_wf_task();
566
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
567
- t.add_timer_fired(timer_started_event_id, "1".to_string());
568
-
569
- // nonlegacy query got here & LA started here
570
- // then next task is incremental w/ legacy query (for impossible query case)
571
- t.add_full_wf_task();
572
-
573
- let tasks = [
574
- hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
575
- {
576
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2));
577
- pr.queries = HashMap::new();
578
- pr.queries.insert(
579
- "q1".to_string(),
580
- WorkflowQuery {
581
- query_type: "query-type".to_string(),
582
- query_args: Some(b"hi".into()),
583
- header: None,
584
- },
585
- );
586
- pr
587
- },
588
- {
589
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(2));
590
- // Strip beginning of history so the only events are WFT sched/started, we need to look
591
- // like we hit the cache
592
- {
593
- let h = pr.history.as_mut().unwrap();
594
- h.events = h.events.split_off(6);
595
- }
596
- // In the nonsense server response case, we attach a legacy query, otherwise this
597
- // response looks like a normal response to a forced WFT heartbeat.
598
- if impossible_query_in_task {
599
- pr.query = Some(WorkflowQuery {
600
- query_type: "query-type".to_string(),
601
- query_args: Some(b"hi".into()),
602
- header: None,
603
- });
604
- }
605
- pr
606
- },
607
- ];
608
- let mut mock = mock_worker_client();
609
- if impossible_query_in_task {
610
- mock.expect_respond_legacy_query()
611
- .times(1)
612
- .returning(move |_, _| Ok(Default::default()));
613
- }
614
- let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
615
- mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
616
- let taskmap = mock.outstanding_task_map.clone().unwrap();
617
- let core = mock_worker(mock);
618
-
619
- let wf_fut = async {
620
- let task = core.poll_workflow_activation().await.unwrap();
621
- assert_matches!(
622
- task.jobs.as_slice(),
623
- &[WorkflowActivationJob {
624
- variant: Some(workflow_activation_job::Variant::InitializeWorkflow(_)),
625
- },]
626
- );
627
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
628
- task.run_id,
629
- start_timer_cmd(1, Duration::from_secs(1)),
630
- ))
631
- .await
632
- .unwrap();
633
-
634
- let task = core.poll_workflow_activation().await.unwrap();
635
- assert_matches!(
636
- task.jobs.as_slice(),
637
- &[WorkflowActivationJob {
638
- variant: Some(workflow_activation_job::Variant::FireTimer(_)),
639
- },]
640
- );
641
- // We want to make sure the weird-looking query gets received while we're working on other
642
- // stuff, so that we don't see the workflow complete and choose to evict.
643
- taskmap.release_run(&task.run_id);
644
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
645
- task.run_id,
646
- schedule_local_activity_cmd(
647
- 1,
648
- "act-id",
649
- ActivityCancellationType::TryCancel,
650
- Duration::from_secs(60),
651
- ),
652
- ))
653
- .await
654
- .unwrap();
655
-
656
- let task = core.poll_workflow_activation().await.unwrap();
657
- // The next task needs to be resolve, since the LA is completed immediately
658
- assert_matches!(
659
- task.jobs.as_slice(),
660
- [WorkflowActivationJob {
661
- variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
662
- }]
663
- );
664
- // Complete workflow
665
- core.complete_execution(&task.run_id).await;
666
-
667
- // Now we will get the query
668
- let task = core.poll_workflow_activation().await.unwrap();
669
- assert_matches!(
670
- task.jobs.as_slice(),
671
- &[WorkflowActivationJob {
672
- variant: Some(workflow_activation_job::Variant::QueryWorkflow(ref q)),
673
- }]
674
- if q.query_id == "q1"
675
- );
676
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
677
- task.run_id,
678
- query_ok("q1", "whatev"),
679
- ))
680
- .await
681
- .unwrap();
682
-
683
- if impossible_query_in_task {
684
- // finish last query
685
- let task = core.poll_workflow_activation().await.unwrap();
686
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
687
- task.run_id,
688
- query_ok(LEGACY_QUERY_ID, "whatev"),
689
- ))
690
- .await
691
- .unwrap();
692
- }
693
- };
694
- let act_fut = async {
695
- let act_task = core.poll_activity_task().await.unwrap();
696
- core.complete_activity_task(ActivityTaskCompletion {
697
- task_token: act_task.task_token,
698
- result: Some(ActivityExecutionResult::ok(vec![1].into())),
699
- })
700
- .await
701
- .unwrap();
702
- };
703
-
704
- join!(wf_fut, act_fut);
705
- core.drain_pollers_and_shutdown().await;
706
- }
707
-
708
- #[tokio::test]
709
- async fn test_schedule_to_start_timeout() {
710
- let mut t = TestHistoryBuilder::default();
711
- t.add_by_type(EventType::WorkflowExecutionStarted);
712
- t.add_full_wf_task();
713
-
714
- let wf_id = "fakeid";
715
- let mock = mock_worker_client();
716
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::ToTaskNum(1)], mock);
717
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
718
-
719
- worker.register_wf(
720
- DEFAULT_WORKFLOW_TYPE.to_owned(),
721
- |ctx: WfContext| async move {
722
- let la_res = ctx
723
- .local_activity(LocalActivityOptions {
724
- activity_type: "echo".to_string(),
725
- input: "hi".as_json_payload().expect("serializes fine"),
726
- // Impossibly small timeout so we timeout in the queue
727
- schedule_to_start_timeout: prost_dur!(from_nanos(1)),
728
- ..Default::default()
729
- })
730
- .await;
731
- assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToStart));
732
- let rfail = la_res.unwrap_failure();
733
- assert_matches!(
734
- rfail.failure_info,
735
- Some(FailureInfo::ActivityFailureInfo(_))
736
- );
737
- assert_matches!(
738
- rfail.cause.unwrap().failure_info,
739
- Some(FailureInfo::TimeoutFailureInfo(_))
740
- );
741
- Ok(().into())
742
- },
743
- );
744
- worker.register_activity(
745
- "echo",
746
- move |_ctx: ActContext, _: String| async move { Ok(()) },
747
- );
748
- worker
749
- .submit_wf(
750
- wf_id.to_owned(),
751
- DEFAULT_WORKFLOW_TYPE.to_owned(),
752
- vec![],
753
- WorkflowOptions::default(),
754
- )
755
- .await
756
- .unwrap();
757
- worker.run_until_done().await.unwrap();
758
- }
759
-
760
- #[rstest::rstest]
761
- #[case::sched_to_start(true)]
762
- #[case::sched_to_close(false)]
763
- #[tokio::test]
764
- async fn test_schedule_to_start_timeout_not_based_on_original_time(
765
- #[case] is_sched_to_start: bool,
766
- ) {
767
- // We used to carry over the schedule time of LAs from the "original" schedule time if these LAs
768
- // created newly after backing off across a timer. That was a mistake, since schedule-to-start
769
- // timeouts should apply to when the new attempt was scheduled. This test verifies:
770
- // * we don't time out on s-t-s timeouts because of that, when the param is true.
771
- // * we do properly time out on s-t-c timeouts when the param is false
772
-
773
- let mut t = TestHistoryBuilder::default();
774
- t.add_by_type(EventType::WorkflowExecutionStarted);
775
- t.add_full_wf_task();
776
- let orig_sched = SystemTime::now().sub(Duration::from_secs(60 * 20));
777
- t.add_local_activity_marker(
778
- 1,
779
- "1",
780
- None,
781
- Some(Failure::application_failure("la failed".to_string(), false)),
782
- |deets| {
783
- // Really old schedule time, which should _not_ count against schedule_to_start
784
- deets.original_schedule_time = Some(orig_sched.into());
785
- // Backoff value must be present since we're simulating timer backoff
786
- deets.backoff = Some(prost_dur!(from_secs(100)));
787
- },
788
- );
789
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
790
- t.add_timer_fired(timer_started_event_id, "1".to_string());
791
- t.add_workflow_task_scheduled_and_started();
792
-
793
- let wf_id = "fakeid";
794
- let mock = mock_worker_client();
795
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
796
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
797
-
798
- let schedule_to_close_timeout = Some(if is_sched_to_start {
799
- // This 60 minute timeout will not have elapsed according to the original
800
- // schedule time in the history.
801
- Duration::from_secs(60 * 60)
802
- } else {
803
- // This 10 minute timeout will have already elapsed
804
- Duration::from_secs(10 * 60)
805
- });
806
-
807
- worker.register_wf(
808
- DEFAULT_WORKFLOW_TYPE.to_owned(),
809
- move |ctx: WfContext| async move {
810
- let la_res = ctx
811
- .local_activity(LocalActivityOptions {
812
- activity_type: "echo".to_string(),
813
- input: "hi".as_json_payload().expect("serializes fine"),
814
- retry_policy: RetryPolicy {
815
- initial_interval: Some(prost_dur!(from_millis(50))),
816
- backoff_coefficient: 1.2,
817
- maximum_interval: None,
818
- maximum_attempts: 5,
819
- non_retryable_error_types: vec![],
820
- },
821
- schedule_to_start_timeout: Some(Duration::from_secs(60)),
822
- schedule_to_close_timeout,
823
- ..Default::default()
824
- })
825
- .await;
826
- if is_sched_to_start {
827
- assert!(la_res.completed_ok());
828
- } else {
829
- assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToClose));
830
- }
831
- Ok(().into())
832
- },
833
- );
834
- worker.register_activity(
835
- "echo",
836
- move |_ctx: ActContext, _: String| async move { Ok(()) },
837
- );
838
- worker
839
- .submit_wf(
840
- wf_id.to_owned(),
841
- DEFAULT_WORKFLOW_TYPE.to_owned(),
842
- vec![],
843
- WorkflowOptions::default(),
844
- )
845
- .await
846
- .unwrap();
847
- worker.run_until_done().await.unwrap();
848
- }
849
-
850
- #[rstest::rstest]
851
- #[tokio::test]
852
- async fn start_to_close_timeout_allows_retries(#[values(true, false)] la_completes: bool) {
853
- let mut t = TestHistoryBuilder::default();
854
- t.add_by_type(EventType::WorkflowExecutionStarted);
855
- t.add_full_wf_task();
856
- if la_completes {
857
- t.add_local_activity_marker(1, "1", Some("hi".into()), None, |_| {});
858
- } else {
859
- t.add_local_activity_marker(
860
- 1,
861
- "1",
862
- None,
863
- Some(Failure::timeout(TimeoutType::StartToClose)),
864
- |_| {},
865
- );
866
- }
867
- t.add_full_wf_task();
868
- t.add_workflow_execution_completed();
869
-
870
- let wf_id = "fakeid";
871
- let mock = mock_worker_client();
872
- let mh = MockPollCfg::from_resp_batches(
873
- wf_id,
874
- t,
875
- [ResponseType::ToTaskNum(1), ResponseType::AllHistory],
876
- mock,
877
- );
878
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
879
-
880
- worker.register_wf(
881
- DEFAULT_WORKFLOW_TYPE.to_owned(),
882
- move |ctx: WfContext| async move {
883
- let la_res = ctx
884
- .local_activity(LocalActivityOptions {
885
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
886
- input: "hi".as_json_payload().expect("serializes fine"),
887
- retry_policy: RetryPolicy {
888
- initial_interval: Some(prost_dur!(from_millis(20))),
889
- backoff_coefficient: 1.0,
890
- maximum_interval: None,
891
- maximum_attempts: 5,
892
- non_retryable_error_types: vec![],
893
- },
894
- start_to_close_timeout: Some(prost_dur!(from_millis(25))),
895
- ..Default::default()
896
- })
897
- .await;
898
- if la_completes {
899
- assert!(la_res.completed_ok());
900
- } else {
901
- assert_eq!(la_res.timed_out(), Some(TimeoutType::StartToClose));
902
- }
903
- Ok(().into())
904
- },
905
- );
906
- let attempts: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
907
- let cancels: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
908
- worker.register_activity(
909
- DEFAULT_ACTIVITY_TYPE,
910
- move |ctx: ActContext, _: String| async move {
911
- // Timeout the first 4 attempts, or all of them if we intend to fail
912
- if attempts.fetch_add(1, Ordering::AcqRel) < 4 || !la_completes {
913
- select! {
914
- _ = tokio::time::sleep(Duration::from_millis(100)) => (),
915
- _ = ctx.cancelled() => {
916
- cancels.fetch_add(1, Ordering::AcqRel);
917
- return Err(ActivityError::cancelled());
918
- }
919
- }
920
- }
921
- Ok(())
922
- },
923
- );
924
- worker
925
- .submit_wf(
926
- wf_id.to_owned(),
927
- DEFAULT_WORKFLOW_TYPE.to_owned(),
928
- vec![],
929
- WorkflowOptions::default(),
930
- )
931
- .await
932
- .unwrap();
933
- worker.run_until_done().await.unwrap();
934
- // Activity should have been attempted all 5 times
935
- assert_eq!(attempts.load(Ordering::Acquire), 5);
936
- let num_cancels = if la_completes { 4 } else { 5 };
937
- assert_eq!(cancels.load(Ordering::Acquire), num_cancels);
938
- }
939
-
940
- #[tokio::test]
941
- async fn wft_failure_cancels_running_las() {
942
- let mut t = TestHistoryBuilder::default();
943
- t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
944
- t.add_full_wf_task();
945
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
946
- t.add_timer_fired(timer_started_event_id, "1".to_string());
947
- t.add_workflow_task_scheduled_and_started();
948
-
949
- let wf_id = "fakeid";
950
- let mock = mock_worker_client();
951
- let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2], mock);
952
- mh.num_expected_fails = 1;
953
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
954
-
955
- worker.register_wf(
956
- DEFAULT_WORKFLOW_TYPE.to_owned(),
957
- |ctx: WfContext| async move {
958
- let la_handle = ctx.local_activity(LocalActivityOptions {
959
- activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
960
- input: "hi".as_json_payload().expect("serializes fine"),
961
- ..Default::default()
962
- });
963
- tokio::join!(
964
- async {
965
- ctx.timer(Duration::from_secs(1)).await;
966
- panic!("ahhh I'm failing wft")
967
- },
968
- la_handle
969
- );
970
- Ok(().into())
971
- },
972
- );
973
- worker.register_activity(
974
- DEFAULT_ACTIVITY_TYPE,
975
- move |ctx: ActContext, _: String| async move {
976
- let res = tokio::time::timeout(Duration::from_millis(500), ctx.cancelled()).await;
977
- if res.is_err() {
978
- panic!("Activity must be cancelled!!!!");
979
- }
980
- Result::<(), _>::Err(ActivityError::cancelled())
981
- },
982
- );
983
- worker
984
- .submit_wf(
985
- wf_id.to_owned(),
986
- DEFAULT_WORKFLOW_TYPE.to_owned(),
987
- vec![],
988
- WorkflowOptions::default(),
989
- )
990
- .await
991
- .unwrap();
992
- worker.run_until_done().await.unwrap();
993
- }
994
-
995
- #[tokio::test]
996
- async fn resolved_las_not_recorded_if_wft_fails_many_times() {
997
- // We shouldn't record any LA results if the workflow activation is repeatedly failing. There
998
- // was an issue that, because we stop reporting WFT failures after 2 tries, this meant the WFT
999
- // was not marked as "completed" and the WFT could accidentally be replied to with LA results.
1000
- let mut t = TestHistoryBuilder::default();
1001
- t.add_by_type(EventType::WorkflowExecutionStarted);
1002
- t.add_workflow_task_scheduled_and_started();
1003
- t.add_workflow_task_failed_with_failure(
1004
- WorkflowTaskFailedCause::Unspecified,
1005
- Default::default(),
1006
- );
1007
- t.add_workflow_task_scheduled_and_started();
1008
-
1009
- let wf_id = "fakeid";
1010
- let mock = mock_worker_client();
1011
- let mut mh = MockPollCfg::from_resp_batches(
1012
- wf_id,
1013
- t,
1014
- [1.into(), ResponseType::AllHistory, ResponseType::AllHistory],
1015
- mock,
1016
- );
1017
- mh.num_expected_fails = 2;
1018
- mh.num_expected_completions = Some(0.into());
1019
- let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
1020
-
1021
- #[allow(unreachable_code)]
1022
- worker.register_wf(
1023
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1024
- WorkflowFunction::new::<_, _, ()>(|ctx: WfContext| async move {
1025
- ctx.local_activity(LocalActivityOptions {
1026
- activity_type: "echo".to_string(),
1027
- input: "hi".as_json_payload().expect("serializes fine"),
1028
- ..Default::default()
1029
- })
1030
- .await;
1031
- panic!()
1032
- }),
1033
- );
1034
- worker.register_activity(
1035
- "echo",
1036
- move |_: ActContext, _: String| async move { Ok(()) },
1037
- );
1038
- worker
1039
- .submit_wf(
1040
- wf_id.to_owned(),
1041
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1042
- vec![],
1043
- WorkflowOptions::default(),
1044
- )
1045
- .await
1046
- .unwrap();
1047
- worker.run_until_done().await.unwrap();
1048
- }
1049
-
1050
- #[tokio::test]
1051
- async fn local_act_records_nonfirst_attempts_ok() {
1052
- let mut t = TestHistoryBuilder::default();
1053
- let wft_timeout = Duration::from_millis(200);
1054
- t.add_wfe_started_with_wft_timeout(wft_timeout);
1055
- t.add_full_wf_task();
1056
- t.add_full_wf_task();
1057
- t.add_full_wf_task();
1058
- t.add_workflow_task_scheduled_and_started();
1059
-
1060
- let wf_id = "fakeid";
1061
- let mock = mock_worker_client();
1062
- let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 3], mock);
1063
- let nonfirst_counts = Arc::new(SegQueue::new());
1064
- let nfc_c = nonfirst_counts.clone();
1065
- mh.completion_mock_fn = Some(Box::new(move |c| {
1066
- nfc_c.push(
1067
- c.metering_metadata
1068
- .nonfirst_local_activity_execution_attempts,
1069
- );
1070
- Ok(Default::default())
1071
- }));
1072
- let mut worker = mock_sdk_cfg(mh, |wc| {
1073
- wc.max_cached_workflows = 1;
1074
- wc.max_outstanding_workflow_tasks = Some(1);
1075
- });
1076
-
1077
- worker.register_wf(
1078
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1079
- |ctx: WfContext| async move {
1080
- ctx.local_activity(LocalActivityOptions {
1081
- activity_type: "echo".to_string(),
1082
- input: "hi".as_json_payload().expect("serializes fine"),
1083
- retry_policy: RetryPolicy {
1084
- initial_interval: Some(prost_dur!(from_millis(10))),
1085
- backoff_coefficient: 1.0,
1086
- maximum_interval: None,
1087
- maximum_attempts: 0,
1088
- non_retryable_error_types: vec![],
1089
- },
1090
- ..Default::default()
1091
- })
1092
- .await;
1093
- Ok(().into())
1094
- },
1095
- );
1096
- worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
1097
- Result::<(), _>::Err(anyhow!("I fail").into())
1098
- });
1099
- worker
1100
- .submit_wf(
1101
- wf_id.to_owned(),
1102
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1103
- vec![],
1104
- WorkflowOptions::default(),
1105
- )
1106
- .await
1107
- .unwrap();
1108
- worker.run_until_done().await.unwrap();
1109
- // 3 workflow tasks
1110
- assert_eq!(nonfirst_counts.len(), 3);
1111
- // First task's non-first count should, of course, be 0
1112
- assert_eq!(nonfirst_counts.pop().unwrap(), 0);
1113
- // Next two, some nonzero amount which could vary based on test load
1114
- assert!(nonfirst_counts.pop().unwrap() > 0);
1115
- assert!(nonfirst_counts.pop().unwrap() > 0);
1116
- }
1117
-
1118
- #[tokio::test]
1119
- async fn local_activities_can_be_delivered_during_shutdown() {
1120
- let wfid = "fake_wf_id";
1121
- let mut t = TestHistoryBuilder::default();
1122
- t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
1123
- t.add_full_wf_task();
1124
- let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1125
- t.add_timer_fired(timer_started_event_id, "1".to_string());
1126
- t.add_workflow_task_scheduled_and_started();
1127
-
1128
- let mock = mock_worker_client();
1129
- let mut mock = single_hist_mock_sg(
1130
- wfid,
1131
- t,
1132
- [ResponseType::ToTaskNum(1), ResponseType::AllHistory],
1133
- mock,
1134
- true,
1135
- );
1136
- mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
1137
- let core = mock_worker(mock);
1138
-
1139
- let task = core.poll_workflow_activation().await.unwrap();
1140
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1141
- task.run_id,
1142
- start_timer_cmd(1, Duration::from_secs(1)),
1143
- ))
1144
- .await
1145
- .unwrap();
1146
-
1147
- let task = core.poll_workflow_activation().await.unwrap();
1148
- // Initiate shutdown once we have the WF activation, but before replying that we want to do an
1149
- // LA
1150
- core.initiate_shutdown();
1151
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1152
- task.run_id,
1153
- ScheduleLocalActivity {
1154
- seq: 1,
1155
- activity_id: "1".to_string(),
1156
- activity_type: "test_act".to_string(),
1157
- start_to_close_timeout: Some(prost_dur!(from_secs(30))),
1158
- ..Default::default()
1159
- }
1160
- .into(),
1161
- ))
1162
- .await
1163
- .unwrap();
1164
-
1165
- let wf_poller = async { core.poll_workflow_activation().await };
1166
-
1167
- let at_poller = async {
1168
- let act_task = core.poll_activity_task().await.unwrap();
1169
- core.complete_activity_task(ActivityTaskCompletion {
1170
- task_token: act_task.task_token,
1171
- result: Some(ActivityExecutionResult::ok(vec![1].into())),
1172
- })
1173
- .await
1174
- .unwrap();
1175
- core.poll_activity_task().await
1176
- };
1177
-
1178
- let (wf_r, act_r) = join!(wf_poller, at_poller);
1179
- assert_matches!(wf_r.unwrap_err(), PollError::ShutDown);
1180
- assert_matches!(act_r.unwrap_err(), PollError::ShutDown);
1181
- }
1182
-
1183
- #[tokio::test]
1184
- async fn queries_can_be_received_while_heartbeating() {
1185
- let wfid = "fake_wf_id";
1186
- let mut t = TestHistoryBuilder::default();
1187
- t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
1188
- t.add_full_wf_task();
1189
- t.add_full_wf_task();
1190
- t.add_full_wf_task();
1191
-
1192
- let tasks = [
1193
- hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
1194
- {
1195
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2));
1196
- pr.queries = HashMap::new();
1197
- pr.queries.insert(
1198
- "q1".to_string(),
1199
- WorkflowQuery {
1200
- query_type: "query-type".to_string(),
1201
- query_args: Some(b"hi".into()),
1202
- header: None,
1203
- },
1204
- );
1205
- pr
1206
- },
1207
- {
1208
- let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(3));
1209
- pr.query = Some(WorkflowQuery {
1210
- query_type: "query-type".to_string(),
1211
- query_args: Some(b"hi".into()),
1212
- header: None,
1213
- });
1214
- pr
1215
- },
1216
- ];
1217
- let mut mock = mock_worker_client();
1218
- mock.expect_respond_legacy_query()
1219
- .times(1)
1220
- .returning(move |_, _| Ok(Default::default()));
1221
- let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
1222
- mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
1223
- let core = mock_worker(mock);
1224
-
1225
- let task = core.poll_workflow_activation().await.unwrap();
1226
- assert_matches!(
1227
- task.jobs.as_slice(),
1228
- &[WorkflowActivationJob {
1229
- variant: Some(workflow_activation_job::Variant::InitializeWorkflow(_)),
1230
- },]
1231
- );
1232
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1233
- task.run_id,
1234
- schedule_local_activity_cmd(
1235
- 1,
1236
- "act-id",
1237
- ActivityCancellationType::TryCancel,
1238
- Duration::from_secs(60),
1239
- ),
1240
- ))
1241
- .await
1242
- .unwrap();
1243
-
1244
- let task = core.poll_workflow_activation().await.unwrap();
1245
- assert_matches!(
1246
- task.jobs.as_slice(),
1247
- &[WorkflowActivationJob {
1248
- variant: Some(workflow_activation_job::Variant::QueryWorkflow(ref q)),
1249
- }]
1250
- if q.query_id == "q1"
1251
- );
1252
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1253
- task.run_id,
1254
- query_ok("q1", "whatev"),
1255
- ))
1256
- .await
1257
- .unwrap();
1258
-
1259
- let task = core.poll_workflow_activation().await.unwrap();
1260
- assert_matches!(
1261
- task.jobs.as_slice(),
1262
- &[WorkflowActivationJob {
1263
- variant: Some(workflow_activation_job::Variant::QueryWorkflow(ref q)),
1264
- }]
1265
- if q.query_id == LEGACY_QUERY_ID
1266
- );
1267
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
1268
- task.run_id,
1269
- query_ok(LEGACY_QUERY_ID, "whatev"),
1270
- ))
1271
- .await
1272
- .unwrap();
1273
-
1274
- // Handle the activity so we can shut down cleanly
1275
- let act_task = core.poll_activity_task().await.unwrap();
1276
- core.complete_activity_task(ActivityTaskCompletion {
1277
- task_token: act_task.task_token,
1278
- result: Some(ActivityExecutionResult::ok(vec![1].into())),
1279
- })
1280
- .await
1281
- .unwrap();
1282
-
1283
- core.drain_pollers_and_shutdown().await;
1284
- }
1285
-
1286
- #[tokio::test]
1287
- async fn local_activity_after_wf_complete_is_discarded() {
1288
- let wfid = "fake_wf_id";
1289
- let mut t = TestHistoryBuilder::default();
1290
- t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
1291
- t.add_full_wf_task();
1292
- t.add_workflow_task_scheduled_and_started();
1293
-
1294
- let mock = mock_worker_client();
1295
- let mut mock_cfg = MockPollCfg::from_resp_batches(
1296
- wfid,
1297
- t,
1298
- [ResponseType::ToTaskNum(1), ResponseType::ToTaskNum(2)],
1299
- mock,
1300
- );
1301
- mock_cfg.make_poll_stream_interminable = true;
1302
- mock_cfg.completion_asserts_from_expectations(|mut asserts| {
1303
- asserts
1304
- .then(move |wft| {
1305
- assert_eq!(wft.commands.len(), 0);
1306
- })
1307
- .then(move |wft| {
1308
- assert_eq!(wft.commands.len(), 2);
1309
- assert_eq!(wft.commands[0].command_type(), CommandType::RecordMarker);
1310
- assert_eq!(
1311
- wft.commands[1].command_type(),
1312
- CommandType::CompleteWorkflowExecution
1313
- );
1314
- });
1315
- });
1316
- let mut mock = build_mock_pollers(mock_cfg);
1317
- mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
1318
- let core = mock_worker(mock);
1319
-
1320
- let barr = Barrier::new(2);
1321
-
1322
- let task = core.poll_workflow_activation().await.unwrap();
1323
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
1324
- task.run_id,
1325
- vec![
1326
- ScheduleLocalActivity {
1327
- seq: 1,
1328
- activity_id: "1".to_string(),
1329
- activity_type: "test_act".to_string(),
1330
- start_to_close_timeout: Some(prost_dur!(from_secs(30))),
1331
- ..Default::default()
1332
- }
1333
- .into(),
1334
- ScheduleLocalActivity {
1335
- seq: 2,
1336
- activity_id: "2".to_string(),
1337
- activity_type: "test_act".to_string(),
1338
- start_to_close_timeout: Some(prost_dur!(from_secs(30))),
1339
- ..Default::default()
1340
- }
1341
- .into(),
1342
- ],
1343
- ))
1344
- .await
1345
- .unwrap();
1346
-
1347
- let wf_poller = async {
1348
- let task = core.poll_workflow_activation().await.unwrap();
1349
- assert_matches!(
1350
- task.jobs.as_slice(),
1351
- [WorkflowActivationJob {
1352
- variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
1353
- }]
1354
- );
1355
- barr.wait().await;
1356
- core.complete_execution(&task.run_id).await;
1357
- };
1358
-
1359
- let at_poller = async {
1360
- let act_task = core.poll_activity_task().await.unwrap();
1361
- core.complete_activity_task(ActivityTaskCompletion {
1362
- task_token: act_task.task_token,
1363
- result: Some(ActivityExecutionResult::ok(vec![1].into())),
1364
- })
1365
- .await
1366
- .unwrap();
1367
- let act_task = core.poll_activity_task().await.unwrap();
1368
- barr.wait().await;
1369
- core.complete_activity_task(ActivityTaskCompletion {
1370
- task_token: act_task.task_token,
1371
- result: Some(ActivityExecutionResult::ok(vec![2].into())),
1372
- })
1373
- .await
1374
- .unwrap();
1375
- };
1376
-
1377
- join!(wf_poller, at_poller);
1378
- core.drain_pollers_and_shutdown().await;
1379
- }
1380
-
1381
- #[tokio::test]
1382
- async fn local_act_retry_explicit_delay() {
1383
- let mut t = TestHistoryBuilder::default();
1384
- t.add_by_type(EventType::WorkflowExecutionStarted);
1385
- t.add_workflow_task_scheduled_and_started();
1386
-
1387
- let wf_id = "fakeid";
1388
- let mock = mock_worker_client();
1389
- let mh = MockPollCfg::from_resp_batches(wf_id, t, [1], mock);
1390
- let mut worker = mock_sdk(mh);
1391
-
1392
- worker.register_wf(
1393
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1394
- move |ctx: WfContext| async move {
1395
- let la_res = ctx
1396
- .local_activity(LocalActivityOptions {
1397
- activity_type: "echo".to_string(),
1398
- input: "hi".as_json_payload().expect("serializes fine"),
1399
- retry_policy: RetryPolicy {
1400
- initial_interval: Some(prost_dur!(from_millis(50))),
1401
- backoff_coefficient: 1.0,
1402
- maximum_attempts: 5,
1403
- ..Default::default()
1404
- },
1405
- ..Default::default()
1406
- })
1407
- .await;
1408
- assert!(la_res.completed_ok());
1409
- Ok(().into())
1410
- },
1411
- );
1412
- let attempts: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
1413
- worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
1414
- // Succeed on 3rd attempt (which is ==2 since fetch_add returns prev val)
1415
- let last_attempt = attempts.fetch_add(1, Ordering::Relaxed);
1416
- if 0 == last_attempt {
1417
- Err(ActivityError::Retryable {
1418
- source: anyhow!("Explicit backoff error"),
1419
- explicit_delay: Some(Duration::from_millis(300)),
1420
- })
1421
- } else if 2 == last_attempt {
1422
- Ok(())
1423
- } else {
1424
- Err(anyhow!("Oh no I failed!").into())
1425
- }
1426
- });
1427
- worker
1428
- .submit_wf(
1429
- wf_id.to_owned(),
1430
- DEFAULT_WORKFLOW_TYPE.to_owned(),
1431
- vec![],
1432
- WorkflowOptions::default(),
1433
- )
1434
- .await
1435
- .unwrap();
1436
- let start = Instant::now();
1437
- worker.run_until_done().await.unwrap();
1438
- let expected_attempts = 3;
1439
- assert_eq!(expected_attempts, attempts.load(Ordering::Relaxed));
1440
- // There will be one 300ms backoff and one 50s backoff, so things should take at least that long
1441
- assert!(start.elapsed() > Duration::from_millis(350));
1442
- }