temporalio 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +180 -7
  3. data/bridge/Cargo.lock +208 -76
  4. data/bridge/Cargo.toml +5 -2
  5. data/bridge/sdk-core/Cargo.toml +1 -1
  6. data/bridge/sdk-core/README.md +20 -10
  7. data/bridge/sdk-core/client/Cargo.toml +1 -1
  8. data/bridge/sdk-core/client/src/lib.rs +227 -59
  9. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  10. data/bridge/sdk-core/client/src/raw.rs +13 -12
  11. data/bridge/sdk-core/client/src/retry.rs +132 -43
  12. data/bridge/sdk-core/core/Cargo.toml +28 -15
  13. data/bridge/sdk-core/core/benches/workflow_replay.rs +13 -10
  14. data/bridge/sdk-core/core/src/abstractions.rs +225 -36
  15. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +217 -79
  16. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  17. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +565 -34
  18. data/bridge/sdk-core/core/src/core_tests/queries.rs +247 -90
  19. data/bridge/sdk-core/core/src/core_tests/workers.rs +3 -5
  20. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
  21. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +430 -67
  22. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  23. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  24. data/bridge/sdk-core/core/src/lib.rs +148 -34
  25. data/bridge/sdk-core/core/src/protosext/mod.rs +1 -1
  26. data/bridge/sdk-core/core/src/replay/mod.rs +185 -41
  27. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  28. data/bridge/sdk-core/core/src/telemetry/metrics.rs +219 -140
  29. data/bridge/sdk-core/core/src/telemetry/mod.rs +326 -315
  30. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +20 -14
  31. data/bridge/sdk-core/core/src/test_help/mod.rs +85 -21
  32. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  33. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  34. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +364 -128
  35. data/bridge/sdk-core/core/src/worker/activities.rs +263 -170
  36. data/bridge/sdk-core/core/src/worker/client/mocks.rs +23 -3
  37. data/bridge/sdk-core/core/src/worker/client.rs +48 -6
  38. data/bridge/sdk-core/core/src/worker/mod.rs +186 -75
  39. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  40. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +13 -24
  41. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +879 -226
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +101 -48
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +8 -12
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -9
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +90 -32
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +6 -9
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -10
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +6 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +160 -83
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +36 -54
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +179 -0
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +104 -157
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +8 -12
  54. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -13
  55. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +10 -4
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -11
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +395 -299
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +12 -20
  60. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +33 -18
  61. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1032 -374
  62. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +525 -392
  63. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  64. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +3 -6
  66. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +456 -681
  69. data/bridge/sdk-core/core-api/Cargo.toml +6 -4
  70. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  71. data/bridge/sdk-core/core-api/src/lib.rs +7 -45
  72. data/bridge/sdk-core/core-api/src/telemetry.rs +141 -0
  73. data/bridge/sdk-core/core-api/src/worker.rs +27 -1
  74. data/bridge/sdk-core/etc/deps.svg +115 -140
  75. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  76. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  77. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  78. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  79. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  80. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  81. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  82. data/bridge/sdk-core/protos/api_upstream/buf.yaml +0 -3
  83. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  84. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  85. data/bridge/sdk-core/protos/api_upstream/{temporal/api/enums/v1/cluster.proto → build/tools.go} +7 -18
  86. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  87. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -9
  88. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +15 -26
  89. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  90. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  91. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +4 -9
  92. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  93. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +10 -8
  94. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +28 -2
  95. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  96. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  97. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  98. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  99. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  100. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  101. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  102. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  103. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  104. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  105. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +62 -26
  106. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  107. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +24 -61
  108. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -21
  109. data/bridge/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  110. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  111. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  112. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +110 -31
  113. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  114. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +4 -4
  115. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  116. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  117. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +3 -2
  118. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +111 -36
  119. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +19 -5
  120. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  121. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  122. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  123. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  124. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  125. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  126. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +9 -0
  127. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +9 -1
  128. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  129. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  130. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  131. data/bridge/sdk-core/sdk/Cargo.toml +4 -3
  132. data/bridge/sdk-core/sdk/src/interceptors.rs +36 -3
  133. data/bridge/sdk-core/sdk/src/lib.rs +94 -25
  134. data/bridge/sdk-core/sdk/src/workflow_context.rs +13 -2
  135. data/bridge/sdk-core/sdk/src/workflow_future.rs +10 -13
  136. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  137. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -2
  138. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +164 -104
  139. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +27 -23
  140. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +252 -74
  141. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  142. data/bridge/sdk-core/test-utils/Cargo.toml +4 -1
  143. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  144. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  145. data/bridge/sdk-core/test-utils/src/lib.rs +161 -50
  146. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  147. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  148. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  149. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  150. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  151. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  152. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +239 -0
  153. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -60
  154. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  155. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  156. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  157. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  158. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  159. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  160. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  161. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  162. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +151 -116
  163. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +54 -0
  164. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  165. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +115 -24
  166. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  167. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  168. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  169. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  170. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  171. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +27 -18
  172. data/bridge/sdk-core/tests/main.rs +8 -16
  173. data/bridge/sdk-core/tests/runner.rs +75 -36
  174. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  175. data/bridge/src/connection.rs +117 -82
  176. data/bridge/src/lib.rs +356 -42
  177. data/bridge/src/runtime.rs +10 -3
  178. data/bridge/src/test_server.rs +153 -0
  179. data/bridge/src/worker.rs +133 -9
  180. data/lib/gen/temporal/api/batch/v1/message_pb.rb +8 -6
  181. data/lib/gen/temporal/api/command/v1/message_pb.rb +10 -16
  182. data/lib/gen/temporal/api/common/v1/message_pb.rb +5 -1
  183. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +2 -1
  184. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +3 -3
  185. data/lib/gen/temporal/api/enums/v1/common_pb.rb +2 -1
  186. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +5 -4
  187. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +9 -1
  188. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +1 -1
  189. data/lib/gen/temporal/api/enums/v1/query_pb.rb +1 -1
  190. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +1 -1
  191. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +1 -1
  192. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +1 -1
  193. data/lib/gen/temporal/api/enums/v1/update_pb.rb +7 -10
  194. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +1 -1
  195. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +1 -1
  196. data/lib/gen/temporal/api/failure/v1/message_pb.rb +1 -1
  197. data/lib/gen/temporal/api/filter/v1/message_pb.rb +1 -1
  198. data/lib/gen/temporal/api/history/v1/message_pb.rb +34 -25
  199. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +2 -1
  200. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +14 -51
  201. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +1 -1
  202. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  203. data/lib/gen/temporal/api/query/v1/message_pb.rb +1 -1
  204. data/lib/gen/temporal/api/replication/v1/message_pb.rb +1 -1
  205. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +22 -1
  206. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  207. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +2 -2
  208. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  209. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  210. data/lib/gen/temporal/api/update/v1/message_pb.rb +49 -3
  211. data/lib/gen/temporal/api/version/v1/message_pb.rb +1 -1
  212. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +2 -1
  213. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +47 -20
  214. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +1 -1
  215. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  216. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  217. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  218. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  219. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  220. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  221. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +28 -21
  222. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +32 -24
  223. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  224. data/lib/temporalio/activity/context.rb +102 -0
  225. data/lib/temporalio/activity/info.rb +67 -0
  226. data/lib/temporalio/activity.rb +85 -0
  227. data/lib/temporalio/bridge/connect_options.rb +15 -0
  228. data/lib/temporalio/bridge/error.rb +8 -0
  229. data/lib/temporalio/bridge/retry_config.rb +24 -0
  230. data/lib/temporalio/bridge/tls_options.rb +19 -0
  231. data/lib/temporalio/bridge.rb +14 -0
  232. data/lib/{temporal → temporalio}/client/implementation.rb +57 -56
  233. data/lib/{temporal → temporalio}/client/workflow_handle.rb +35 -35
  234. data/lib/{temporal → temporalio}/client.rb +19 -32
  235. data/lib/temporalio/connection/retry_config.rb +44 -0
  236. data/lib/temporalio/connection/service.rb +20 -0
  237. data/lib/temporalio/connection/test_service.rb +92 -0
  238. data/lib/temporalio/connection/tls_options.rb +51 -0
  239. data/lib/temporalio/connection/workflow_service.rb +731 -0
  240. data/lib/temporalio/connection.rb +86 -0
  241. data/lib/{temporal → temporalio}/data_converter.rb +76 -35
  242. data/lib/{temporal → temporalio}/error/failure.rb +6 -6
  243. data/lib/{temporal → temporalio}/error/workflow_failure.rb +4 -2
  244. data/lib/{temporal → temporalio}/errors.rb +19 -1
  245. data/lib/{temporal → temporalio}/failure_converter/base.rb +5 -5
  246. data/lib/{temporal → temporalio}/failure_converter/basic.rb +58 -52
  247. data/lib/temporalio/failure_converter.rb +7 -0
  248. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  249. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  250. data/lib/{temporal → temporalio}/interceptor/chain.rb +7 -6
  251. data/lib/{temporal → temporalio}/interceptor/client.rb +27 -2
  252. data/lib/temporalio/interceptor.rb +22 -0
  253. data/lib/{temporal → temporalio}/payload_codec/base.rb +5 -5
  254. data/lib/{temporal → temporalio}/payload_converter/base.rb +3 -3
  255. data/lib/{temporal → temporalio}/payload_converter/bytes.rb +4 -3
  256. data/lib/{temporal → temporalio}/payload_converter/composite.rb +7 -5
  257. data/lib/{temporal → temporalio}/payload_converter/encoding_base.rb +4 -4
  258. data/lib/{temporal → temporalio}/payload_converter/json.rb +4 -3
  259. data/lib/{temporal → temporalio}/payload_converter/nil.rb +4 -3
  260. data/lib/temporalio/payload_converter.rb +14 -0
  261. data/lib/{temporal → temporalio}/retry_policy.rb +17 -7
  262. data/lib/{temporal → temporalio}/retry_state.rb +1 -1
  263. data/lib/temporalio/runtime.rb +25 -0
  264. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  265. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  266. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  267. data/lib/temporalio/testing.rb +175 -0
  268. data/lib/{temporal → temporalio}/timeout_type.rb +2 -2
  269. data/lib/temporalio/version.rb +3 -0
  270. data/lib/temporalio/worker/activity_runner.rb +114 -0
  271. data/lib/temporalio/worker/activity_worker.rb +164 -0
  272. data/lib/temporalio/worker/reactor.rb +46 -0
  273. data/lib/temporalio/worker/runner.rb +63 -0
  274. data/lib/temporalio/worker/sync_worker.rb +124 -0
  275. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  276. data/lib/temporalio/worker.rb +204 -0
  277. data/lib/temporalio/workflow/async.rb +46 -0
  278. data/lib/{temporal → temporalio}/workflow/execution_info.rb +4 -4
  279. data/lib/{temporal → temporalio}/workflow/execution_status.rb +1 -1
  280. data/lib/temporalio/workflow/future.rb +138 -0
  281. data/lib/{temporal → temporalio}/workflow/id_reuse_policy.rb +6 -6
  282. data/lib/temporalio/workflow/info.rb +76 -0
  283. data/lib/{temporal → temporalio}/workflow/query_reject_condition.rb +5 -5
  284. data/lib/temporalio.rb +12 -3
  285. data/temporalio.gemspec +11 -6
  286. metadata +137 -64
  287. data/bridge/sdk-core/Cargo.lock +0 -2606
  288. data/bridge/sdk-core/bridge-ffi/Cargo.toml +0 -24
  289. data/bridge/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  290. data/bridge/sdk-core/bridge-ffi/build.rs +0 -25
  291. data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -249
  292. data/bridge/sdk-core/bridge-ffi/src/lib.rs +0 -825
  293. data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +0 -211
  294. data/bridge/sdk-core/core/src/log_export.rs +0 -62
  295. data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
  296. data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
  297. data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
  298. data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  299. data/bridge/sdk-core/sdk/src/conversions.rs +0 -8
  300. data/lib/bridge.so +0 -0
  301. data/lib/gen/temporal/api/cluster/v1/message_pb.rb +0 -67
  302. data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +0 -26
  303. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
  304. data/lib/temporal/bridge.rb +0 -14
  305. data/lib/temporal/connection.rb +0 -736
  306. data/lib/temporal/failure_converter.rb +0 -8
  307. data/lib/temporal/payload_converter.rb +0 -14
  308. data/lib/temporal/runtime.rb +0 -22
  309. data/lib/temporal/version.rb +0 -3
  310. data/lib/temporal.rb +0 -8
@@ -4,15 +4,17 @@ use crate::{
4
4
  build_fake_worker, build_mock_pollers, canned_histories, gen_assert_and_reply,
5
5
  mock_manual_poller, mock_poller, mock_poller_from_resps, mock_worker, poll_and_reply,
6
6
  single_hist_mock_sg, test_worker_cfg, MockPollCfg, MockWorkerInputs, MocksHolder,
7
- ResponseType, WorkflowCachingPolicy, TEST_Q,
7
+ QueueResponse, ResponseType, WorkerExt, WorkflowCachingPolicy, TEST_Q,
8
8
  },
9
9
  worker::client::mocks::{mock_manual_workflow_client, mock_workflow_client},
10
10
  ActivityHeartbeat, Worker, WorkerConfigBuilder,
11
11
  };
12
12
  use futures::FutureExt;
13
+ use itertools::Itertools;
13
14
  use std::{
14
15
  cell::RefCell,
15
16
  collections::{hash_map::Entry, HashMap, VecDeque},
17
+ future,
16
18
  rc::Rc,
17
19
  sync::{
18
20
  atomic::{AtomicUsize, Ordering},
@@ -22,8 +24,10 @@ use std::{
22
24
  };
23
25
  use temporal_client::WorkflowOptions;
24
26
  use temporal_sdk::{ActivityOptions, WfContext};
25
- use temporal_sdk_core_api::{errors::CompleteActivityError, Worker as WorkerTrait};
26
- use temporal_sdk_core_protos::temporal::api::command::v1::ScheduleActivityTaskCommandAttributes;
27
+ use temporal_sdk_core_api::{
28
+ errors::{CompleteActivityError, PollActivityError},
29
+ Worker as WorkerTrait,
30
+ };
27
31
  use temporal_sdk_core_protos::{
28
32
  coresdk::{
29
33
  activity_result::{
@@ -40,8 +44,11 @@ use temporal_sdk_core_protos::{
40
44
  ActivityTaskCompletion,
41
45
  },
42
46
  temporal::api::{
43
- command::v1::command::Attributes,
47
+ command::v1::{command::Attributes, ScheduleActivityTaskCommandAttributes},
44
48
  enums::v1::EventType,
49
+ history::v1::{
50
+ history_event::Attributes as EventAttributes, ActivityTaskScheduledEventAttributes,
51
+ },
45
52
  workflowservice::v1::{
46
53
  PollActivityTaskQueueResponse, RecordActivityTaskHeartbeatResponse,
47
54
  RespondActivityTaskCanceledResponse, RespondActivityTaskCompletedResponse,
@@ -52,6 +59,7 @@ use temporal_sdk_core_protos::{
52
59
  };
53
60
  use temporal_sdk_core_test_utils::{fanout_tasks, start_timer_cmd, TestWorker};
54
61
  use tokio::{sync::Barrier, time::sleep};
62
+ use tokio_util::sync::CancellationToken;
55
63
 
56
64
  #[tokio::test]
57
65
  async fn max_activities_respected() {
@@ -121,7 +129,7 @@ async fn activity_not_found_returns_ok() {
121
129
  })
122
130
  .await
123
131
  .unwrap();
124
- core.shutdown().await;
132
+ core.drain_activity_poller_and_shutdown().await;
125
133
  }
126
134
 
127
135
  #[tokio::test]
@@ -217,12 +225,14 @@ async fn heartbeats_report_cancels_only_once() {
217
225
  })
218
226
  .await
219
227
  .unwrap();
220
- core.shutdown().await;
228
+ core.drain_activity_poller_and_shutdown().await;
221
229
  }
222
230
 
223
231
  #[tokio::test]
224
232
  async fn activity_cancel_interrupts_poll() {
225
233
  let mut mock_poller = mock_manual_poller();
234
+ let shutdown_token = CancellationToken::new();
235
+ let shutdown_token_clone = shutdown_token.clone();
226
236
  let mut poll_resps = VecDeque::from(vec![
227
237
  async {
228
238
  Some(Ok(PollActivityTaskQueueResponse {
@@ -237,10 +247,15 @@ async fn activity_cancel_interrupts_poll() {
237
247
  Some(Ok(Default::default()))
238
248
  }
239
249
  .boxed(),
250
+ async move {
251
+ shutdown_token.cancelled().await;
252
+ None
253
+ }
254
+ .boxed(),
240
255
  ]);
241
256
  mock_poller
242
257
  .expect_poll()
243
- .times(2)
258
+ .times(3)
244
259
  .returning(move || poll_resps.pop_front().unwrap());
245
260
 
246
261
  let mut mock_client = mock_manual_workflow_client();
@@ -289,11 +304,12 @@ async fn activity_cancel_interrupts_poll() {
289
304
  }
290
305
  ).await.unwrap();
291
306
  last_finisher.store(2, Ordering::SeqCst);
307
+ shutdown_token_clone.cancel();
292
308
  }
293
309
  };
294
310
  // So that we know we blocked
295
311
  assert_eq!(last_finisher.load(Ordering::Acquire), 2);
296
- core.shutdown().await;
312
+ core.drain_activity_poller_and_shutdown().await;
297
313
  }
298
314
 
299
315
  #[tokio::test]
@@ -342,13 +358,10 @@ async fn many_concurrent_heartbeat_cancels() {
342
358
  })
343
359
  .collect::<Vec<_>>(),
344
360
  );
345
- // Because the mock is so fast, it's possible it can return before the cancel channel in
346
- // the activity task poll selector. So, the final poll when there are no more tasks must
347
- // take a while.
348
361
  poll_resps.push_back(
349
362
  async {
350
- sleep(Duration::from_secs(10)).await;
351
- unreachable!("Long poll")
363
+ future::pending::<()>().await;
364
+ unreachable!()
352
365
  }
353
366
  .boxed(),
354
367
  );
@@ -431,13 +444,13 @@ async fn many_concurrent_heartbeat_cancels() {
431
444
  })
432
445
  .await;
433
446
 
434
- worker.shutdown().await;
447
+ worker.drain_activity_poller_and_shutdown().await;
435
448
  }
436
449
 
437
450
  #[tokio::test]
438
451
  async fn activity_timeout_no_double_resolve() {
439
452
  let t = canned_histories::activity_double_resolve_repro();
440
- let core = build_fake_worker("fake_wf_id", t, &[3]);
453
+ let core = build_fake_worker("fake_wf_id", t, [3]);
441
454
  let activity_id = 1;
442
455
 
443
456
  poll_and_reply(
@@ -483,7 +496,7 @@ async fn activity_timeout_no_double_resolve() {
483
496
  )
484
497
  .await;
485
498
 
486
- core.shutdown().await;
499
+ core.drain_pollers_and_shutdown().await;
487
500
  }
488
501
 
489
502
  #[tokio::test]
@@ -529,7 +542,7 @@ async fn can_heartbeat_acts_during_shutdown() {
529
542
  })
530
543
  .await
531
544
  .unwrap();
532
- shutdown_fut.await;
545
+ core.drain_activity_poller_and_shutdown().await;
533
546
  }
534
547
 
535
548
  /// Verifies that if a user has tried to record a heartbeat and then immediately after failed the
@@ -580,7 +593,7 @@ async fn complete_act_with_fail_flushes_heartbeat() {
580
593
  })
581
594
  .await
582
595
  .unwrap();
583
- core.shutdown().await;
596
+ core.drain_activity_poller_and_shutdown().await;
584
597
 
585
598
  // Verify the last seen call to record a heartbeat had the last detail payload
586
599
  let last_seen_payload = &last_seen_payload.take().unwrap().payloads[0];
@@ -613,26 +626,20 @@ async fn max_tq_acts_set_passed_to_poll_properly() {
613
626
  worker.poll_activity_task().await.unwrap();
614
627
  }
615
628
 
616
- /// This test verifies that activity tasks which come as replies to completing a WFT are properly
617
- /// delivered via polling.
629
+ /// This test doesn't test the real worker config since [mock_worker] bypasses the worker
630
+ /// constructor, [mock_worker] will not pass an activity poller to the worker when
631
+ /// `no_remote_activities` is set to `true`.
618
632
  #[tokio::test]
619
- async fn activity_tasks_from_completion_are_delivered() {
633
+ async fn no_eager_activities_requested_when_worker_options_disable_remote_activities() {
620
634
  let wfid = "fake_wf_id";
621
635
  let mut t = TestHistoryBuilder::default();
622
636
  t.add_by_type(EventType::WorkflowExecutionStarted);
623
637
  t.add_full_wf_task();
624
- let act_same_queue_sched_id = t.add_activity_task_scheduled("act_id_same_queue");
625
- let act_different_queue_sched_id = t.add_activity_task_scheduled("act_id_different_queue");
626
- let act_same_queue_start_id = t.add_activity_task_started(act_same_queue_sched_id);
627
- t.add_activity_task_completed(
628
- act_same_queue_sched_id,
629
- act_same_queue_start_id,
630
- b"hi".into(),
631
- );
638
+ let scheduled_event_id = t.add_activity_task_scheduled("act_id");
639
+ let started_event_id = t.add_activity_task_started(scheduled_event_id);
640
+ t.add_activity_task_completed(scheduled_event_id, started_event_id, b"hi".into());
632
641
  t.add_full_wf_task();
633
- t.add_activity_task_cancel_requested(act_different_queue_sched_id);
634
642
  t.add_workflow_execution_completed();
635
-
636
643
  let num_eager_requested = Arc::new(AtomicUsize::new(0));
637
644
  // Clone it to move into the callback below
638
645
  let num_eager_requested_clone = num_eager_requested.clone();
@@ -658,65 +665,171 @@ async fn activity_tasks_from_completion_are_delivered() {
658
665
  num_eager_requested_clone.store(count, Ordering::Relaxed);
659
666
  Ok(RespondWorkflowTaskCompletedResponse {
660
667
  workflow_task: None,
661
- activity_tasks: vec![PollActivityTaskQueueResponse {
662
- task_token: vec![1],
663
- activity_id: "act_id_same_queue".to_string(),
664
- ..Default::default()
665
- }],
668
+ activity_tasks: vec![],
669
+ reset_history_event_id: 0,
666
670
  })
667
671
  });
668
- mock.expect_complete_activity_task()
669
- .times(1)
670
- .returning(|_, _| Ok(RespondActivityTaskCompletedResponse::default()));
671
672
  let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
672
673
  let mut mock_poller = mock_manual_poller();
673
674
  mock_poller
674
675
  .expect_poll()
675
676
  .returning(|| futures::future::pending().boxed());
676
677
  mock.set_act_poller(Box::new(mock_poller));
677
- mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
678
+ mock.worker_cfg(|wc| {
679
+ wc.max_cached_workflows = 2;
680
+ wc.no_remote_activities = true;
681
+ });
678
682
  let core = mock_worker(mock);
679
683
 
684
+ // Test start
680
685
  let wf_task = core.poll_workflow_activation().await.unwrap();
686
+ let cmds = vec![ScheduleActivity {
687
+ seq: 1,
688
+ activity_id: "act_id".to_string(),
689
+ task_queue: TEST_Q.to_string(),
690
+ cancellation_type: ActivityCancellationType::TryCancel as i32,
691
+ ..Default::default()
692
+ }
693
+ .into()];
694
+
681
695
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
682
696
  wf_task.run_id,
683
- vec![
697
+ cmds,
698
+ ))
699
+ .await
700
+ .unwrap();
701
+
702
+ core.drain_pollers_and_shutdown().await;
703
+
704
+ assert_eq!(num_eager_requested.load(Ordering::Relaxed), 0);
705
+ }
706
+
707
+ /// This test verifies that activity tasks which come as replies to completing a WFT are properly
708
+ /// delivered via polling.
709
+ #[tokio::test]
710
+ async fn activity_tasks_from_completion_are_delivered() {
711
+ // Construct the history - one task with 5 activities, 4 on the same task queue, and 1 on a
712
+ // different queue, 3 activities will be executed eagerly as specified by the
713
+ // MAX_EAGER_ACTIVITY_RESERVATIONS_PER_WORKFLOW_TASK constant.
714
+ let wfid = "fake_wf_id";
715
+ let mut t = TestHistoryBuilder::default();
716
+ t.add_by_type(EventType::WorkflowExecutionStarted);
717
+ t.add_full_wf_task();
718
+ let act_same_queue_scheduled_ids = (1..4)
719
+ .map(|i| t.add_activity_task_scheduled(format!("act_id_{i}_same_queue")))
720
+ .collect_vec();
721
+ t.add_activity_task_scheduled("act_id_same_queue_not_eager");
722
+ t.add_activity_task_scheduled("act_id_different_queue");
723
+ for scheduled_event_id in act_same_queue_scheduled_ids {
724
+ let started_event_id = t.add_activity_task_started(scheduled_event_id);
725
+ t.add_activity_task_completed(scheduled_event_id, started_event_id, b"hi".into());
726
+ }
727
+ t.add_full_wf_task();
728
+ t.add_workflow_execution_completed();
729
+
730
+ let num_eager_requested = Arc::new(AtomicUsize::new(0));
731
+ // Clone it to move into the callback below
732
+ let num_eager_requested_clone = num_eager_requested.clone();
733
+
734
+ let mut mock = mock_workflow_client();
735
+ mock.expect_complete_workflow_task()
736
+ .times(1)
737
+ .returning(move |req| {
738
+ // Store the number of eager activities requested to be checked below
739
+ let count = req
740
+ .commands
741
+ .into_iter()
742
+ .filter(|c| match c.attributes {
743
+ Some(Attributes::ScheduleActivityTaskCommandAttributes(
744
+ ScheduleActivityTaskCommandAttributes {
745
+ request_eager_execution,
746
+ ..
747
+ },
748
+ )) => request_eager_execution,
749
+ _ => false,
750
+ })
751
+ .count();
752
+ num_eager_requested_clone.store(count, Ordering::Relaxed);
753
+ Ok(RespondWorkflowTaskCompletedResponse {
754
+ workflow_task: None,
755
+ activity_tasks: (1..4)
756
+ .map(|i| PollActivityTaskQueueResponse {
757
+ task_token: vec![i],
758
+ activity_id: format!("act_id_{i}_same_queue"),
759
+ ..Default::default()
760
+ })
761
+ .collect_vec(),
762
+ reset_history_event_id: 0,
763
+ })
764
+ });
765
+ mock.expect_complete_activity_task()
766
+ .times(3)
767
+ .returning(|_, _| Ok(RespondActivityTaskCompletedResponse::default()));
768
+ let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
769
+ let act_tasks: Vec<QueueResponse<PollActivityTaskQueueResponse>> = vec![];
770
+ mock.set_act_poller(mock_poller_from_resps(act_tasks));
771
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
772
+ let core = mock_worker(mock);
773
+
774
+ // Test start
775
+ let wf_task = core.poll_workflow_activation().await.unwrap();
776
+ let mut cmds = (1..4)
777
+ .map(|seq| {
684
778
  ScheduleActivity {
685
- seq: 1,
686
- activity_id: "act_id_same_queue".to_string(),
779
+ seq,
780
+ activity_id: format!("act_id_{seq}_same_queue"),
687
781
  task_queue: TEST_Q.to_string(),
688
782
  cancellation_type: ActivityCancellationType::TryCancel as i32,
689
783
  ..Default::default()
690
784
  }
691
- .into(),
692
- ScheduleActivity {
693
- seq: 2,
694
- activity_id: "act_id_different_queue".to_string(),
695
- task_queue: "different_queue".to_string(),
696
- cancellation_type: ActivityCancellationType::Abandon as i32,
697
- ..Default::default()
698
- }
699
- .into(),
700
- ],
785
+ .into()
786
+ })
787
+ .collect_vec();
788
+ cmds.push(
789
+ ScheduleActivity {
790
+ seq: 4,
791
+ activity_id: "act_id_same_queue_not_eager".to_string(),
792
+ task_queue: TEST_Q.to_string(),
793
+ cancellation_type: ActivityCancellationType::TryCancel as i32,
794
+ ..Default::default()
795
+ }
796
+ .into(),
797
+ );
798
+ cmds.push(
799
+ ScheduleActivity {
800
+ seq: 5,
801
+ activity_id: "act_id_different_queue".to_string(),
802
+ task_queue: "different_queue".to_string(),
803
+ cancellation_type: ActivityCancellationType::Abandon as i32,
804
+ ..Default::default()
805
+ }
806
+ .into(),
807
+ );
808
+
809
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
810
+ wf_task.run_id,
811
+ cmds,
701
812
  ))
702
813
  .await
703
814
  .unwrap();
704
815
 
705
- // We should see the activity when we poll now
706
- let act_task = core.poll_activity_task().await.unwrap();
707
- assert_eq!(act_task.task_token, vec![1]);
816
+ // We should see the 3 eager activities when we poll now
817
+ for i in 1..4 {
818
+ let act_task = core.poll_activity_task().await.unwrap();
819
+ assert_eq!(act_task.task_token, vec![i]);
708
820
 
709
- core.complete_activity_task(ActivityTaskCompletion {
710
- task_token: act_task.task_token.clone(),
711
- result: Some(ActivityExecutionResult::ok("hi".into())),
712
- })
713
- .await
714
- .unwrap();
821
+ core.complete_activity_task(ActivityTaskCompletion {
822
+ task_token: act_task.task_token.clone(),
823
+ result: Some(ActivityExecutionResult::ok("hi".into())),
824
+ })
825
+ .await
826
+ .unwrap();
827
+ }
715
828
 
716
- core.shutdown().await;
829
+ core.drain_activity_poller_and_shutdown().await;
717
830
 
718
831
  // Verify only a single eager activity was scheduled (the one on our worker's task queue)
719
- assert_eq!(num_eager_requested.load(Ordering::Relaxed), 1);
832
+ assert_eq!(num_eager_requested.load(Ordering::Relaxed), 3);
720
833
  }
721
834
 
722
835
  #[tokio::test]
@@ -725,11 +838,23 @@ async fn activity_tasks_from_completion_reserve_slots() {
725
838
  let mut t = TestHistoryBuilder::default();
726
839
  t.add_by_type(EventType::WorkflowExecutionStarted);
727
840
  t.add_full_wf_task();
728
- let schedid = t.add_activity_task_scheduled("1");
841
+ let schedid = t.add(EventAttributes::ActivityTaskScheduledEventAttributes(
842
+ ActivityTaskScheduledEventAttributes {
843
+ activity_id: "1".to_string(),
844
+ activity_type: Some("act1".into()),
845
+ ..Default::default()
846
+ },
847
+ ));
729
848
  let startid = t.add_activity_task_started(schedid);
730
849
  t.add_activity_task_completed(schedid, startid, b"hi".into());
731
850
  t.add_full_wf_task();
732
- let schedid = t.add_activity_task_scheduled("2");
851
+ let schedid = t.add(EventAttributes::ActivityTaskScheduledEventAttributes(
852
+ ActivityTaskScheduledEventAttributes {
853
+ activity_id: "2".to_string(),
854
+ activity_type: Some("act2".into()),
855
+ ..Default::default()
856
+ },
857
+ ));
733
858
  let startid = t.add_activity_task_started(schedid);
734
859
  t.add_activity_task_completed(schedid, startid, b"hi".into());
735
860
  t.add_full_wf_task();
@@ -799,19 +924,25 @@ async fn activity_tasks_from_completion_reserve_slots() {
799
924
  // First poll for activities twice, occupying both slots
800
925
  let at1 = core.poll_activity_task().await.unwrap();
801
926
  let at2 = core.poll_activity_task().await.unwrap();
927
+ let workflow_complete_token = CancellationToken::new();
928
+ let workflow_complete_token_clone = workflow_complete_token.clone();
802
929
 
803
- worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
804
- ctx.activity(ActivityOptions {
805
- activity_type: "act1".to_string(),
806
- ..Default::default()
807
- })
808
- .await;
809
- ctx.activity(ActivityOptions {
810
- activity_type: "act2".to_string(),
811
- ..Default::default()
812
- })
813
- .await;
814
- Ok(().into())
930
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| {
931
+ let complete_token = workflow_complete_token.clone();
932
+ async move {
933
+ ctx.activity(ActivityOptions {
934
+ activity_type: "act1".to_string(),
935
+ ..Default::default()
936
+ })
937
+ .await;
938
+ ctx.activity(ActivityOptions {
939
+ activity_type: "act2".to_string(),
940
+ ..Default::default()
941
+ })
942
+ .await;
943
+ complete_token.cancel();
944
+ Ok(().into())
945
+ }
815
946
  });
816
947
 
817
948
  worker
@@ -838,6 +969,13 @@ async fn activity_tasks_from_completion_reserve_slots() {
838
969
  .await
839
970
  .unwrap();
840
971
  barr.wait().await;
972
+ // Wait for workflow to complete in order for all eager activities to be requested before shutting down.
973
+ // After shutdown, no eager activities slots can be allocated.
974
+ workflow_complete_token_clone.cancelled().await;
975
+ core.initiate_shutdown();
976
+ // Even though this test requests eager activity tasks, none are returned in poll responses.
977
+ let err = core.poll_activity_task().await.unwrap_err();
978
+ assert_matches!(err, PollActivityError::ShutDown);
841
979
  };
842
980
  // This wf poll should *not* set the flag that it wants tasks back since both slots are
843
981
  // occupied
@@ -871,7 +1009,7 @@ async fn retryable_net_error_exhaustion_is_nonfatal() {
871
1009
  })
872
1010
  .await
873
1011
  .unwrap();
874
- core.shutdown().await;
1012
+ core.drain_activity_poller_and_shutdown().await;
875
1013
  }
876
1014
 
877
1015
  #[tokio::test]
@@ -1,4 +1,5 @@
1
1
  use crate::{
2
+ internal_flags::CoreInternalFlags,
2
3
  replay::DEFAULT_WORKFLOW_TYPE,
3
4
  test_help::{canned_histories, mock_sdk, mock_sdk_cfg, MockPollCfg, ResponseType},
4
5
  worker::client::mocks::mock_workflow_client,
@@ -8,8 +9,13 @@ use std::{
8
9
  time::Duration,
9
10
  };
10
11
  use temporal_client::WorkflowOptions;
11
- use temporal_sdk::{WfContext, WorkflowResult};
12
- use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowTaskFailedCause;
12
+ use temporal_sdk::{
13
+ ActivityOptions, ChildWorkflowOptions, LocalActivityOptions, WfContext, WorkflowResult,
14
+ };
15
+ use temporal_sdk_core_protos::{
16
+ temporal::api::{enums::v1::WorkflowTaskFailedCause, failure::v1::Failure},
17
+ DEFAULT_ACTIVITY_TYPE,
18
+ };
13
19
 
14
20
  static DID_FAIL: AtomicBool = AtomicBool::new(false);
15
21
  pub async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
@@ -105,3 +111,160 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
105
111
  // timer and proceed without restarting
106
112
  assert_eq!(2, started_count.load(Ordering::Relaxed));
107
113
  }
114
+
115
+ #[rstest::rstest]
116
+ #[tokio::test]
117
+ async fn activity_id_or_type_change_is_nondeterministic(
118
+ #[values(true, false)] use_cache: bool,
119
+ #[values(true, false)] id_change: bool,
120
+ #[values(true, false)] local_act: bool,
121
+ ) {
122
+ let wf_id = "fakeid";
123
+ let wf_type = DEFAULT_WORKFLOW_TYPE;
124
+ let mut t = if local_act {
125
+ canned_histories::single_local_activity("1")
126
+ } else {
127
+ canned_histories::single_activity("1")
128
+ };
129
+ t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
130
+ let mock = mock_workflow_client();
131
+ let mut mh = MockPollCfg::from_resp_batches(
132
+ wf_id,
133
+ t,
134
+ // Two polls are needed, since the first will fail
135
+ [ResponseType::AllHistory, ResponseType::AllHistory],
136
+ mock,
137
+ );
138
+ // We should see one wft failure which has nondeterminism cause
139
+ mh.num_expected_fails = 1;
140
+ mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
141
+ let should_contain = if id_change {
142
+ "does not match activity id"
143
+ } else {
144
+ "does not match activity type"
145
+ };
146
+ matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
147
+ && matches!(f, Some(Failure {
148
+ message,
149
+ ..
150
+ }) if message.contains(should_contain))
151
+ });
152
+ let mut worker = mock_sdk_cfg(mh, |cfg| {
153
+ if use_cache {
154
+ cfg.max_cached_workflows = 2;
155
+ }
156
+ });
157
+
158
+ worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
159
+ if local_act {
160
+ ctx.local_activity(if id_change {
161
+ LocalActivityOptions {
162
+ activity_id: Some("I'm bad and wrong!".to_string()),
163
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
164
+ ..Default::default()
165
+ }
166
+ } else {
167
+ LocalActivityOptions {
168
+ activity_type: "not the default act type".to_string(),
169
+ ..Default::default()
170
+ }
171
+ })
172
+ .await;
173
+ } else {
174
+ ctx.activity(if id_change {
175
+ ActivityOptions {
176
+ activity_id: Some("I'm bad and wrong!".to_string()),
177
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
178
+ ..Default::default()
179
+ }
180
+ } else {
181
+ ActivityOptions {
182
+ activity_type: "not the default act type".to_string(),
183
+ ..Default::default()
184
+ }
185
+ })
186
+ .await;
187
+ }
188
+ Ok(().into())
189
+ });
190
+
191
+ worker
192
+ .submit_wf(
193
+ wf_id.to_owned(),
194
+ wf_type.to_owned(),
195
+ vec![],
196
+ WorkflowOptions::default(),
197
+ )
198
+ .await
199
+ .unwrap();
200
+ worker.run_until_done().await.unwrap();
201
+ }
202
+
203
+ #[rstest::rstest]
204
+ #[tokio::test]
205
+ async fn child_wf_id_or_type_change_is_nondeterministic(
206
+ #[values(true, false)] use_cache: bool,
207
+ #[values(true, false)] id_change: bool,
208
+ ) {
209
+ let wf_id = "fakeid";
210
+ let wf_type = DEFAULT_WORKFLOW_TYPE;
211
+ let mut t = canned_histories::single_child_workflow("1");
212
+ t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
213
+ let mock = mock_workflow_client();
214
+ let mut mh = MockPollCfg::from_resp_batches(
215
+ wf_id,
216
+ t,
217
+ // Two polls are needed, since the first will fail
218
+ [ResponseType::AllHistory, ResponseType::AllHistory],
219
+ mock,
220
+ );
221
+ // We should see one wft failure which has nondeterminism cause
222
+ mh.num_expected_fails = 1;
223
+ mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
224
+ let should_contain = if id_change {
225
+ "does not match child workflow id"
226
+ } else {
227
+ "does not match child workflow type"
228
+ };
229
+ matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
230
+ && matches!(f, Some(Failure {
231
+ message,
232
+ ..
233
+ }) if message.contains(should_contain))
234
+ });
235
+ let mut worker = mock_sdk_cfg(mh, |cfg| {
236
+ if use_cache {
237
+ cfg.max_cached_workflows = 2;
238
+ }
239
+ });
240
+
241
+ worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
242
+ ctx.child_workflow(if id_change {
243
+ ChildWorkflowOptions {
244
+ workflow_id: "I'm bad and wrong!".to_string(),
245
+ workflow_type: DEFAULT_ACTIVITY_TYPE.to_string(),
246
+ ..Default::default()
247
+ }
248
+ } else {
249
+ ChildWorkflowOptions {
250
+ workflow_id: "1".to_string(),
251
+ workflow_type: "not the child wf type".to_string(),
252
+ ..Default::default()
253
+ }
254
+ })
255
+ .start(&ctx)
256
+ .await;
257
+ Ok(().into())
258
+ });
259
+
260
+ worker
261
+ .submit_wf(
262
+ wf_id.to_owned(),
263
+ wf_type.to_owned(),
264
+ vec![],
265
+ WorkflowOptions::default(),
266
+ )
267
+ .await
268
+ .unwrap();
269
+ worker.run_until_done().await.unwrap();
270
+ }