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
@@ -1,43 +1,45 @@
1
- use crate::telemetry::{default_resource, metrics::SDKAggSelector};
1
+ use crate::telemetry::default_resource;
2
2
  use hyper::{
3
3
  header::CONTENT_TYPE,
4
+ server::conn::AddrIncoming,
4
5
  service::{make_service_fn, service_fn},
5
6
  Body, Method, Request, Response, Server,
6
7
  };
7
- use opentelemetry::{
8
- metrics::MetricsError,
9
- sdk::{
10
- export::metrics::aggregation::TemporalitySelector,
11
- metrics::{controllers, processors},
12
- },
8
+ use opentelemetry::sdk::{
9
+ export::metrics::{aggregation::TemporalitySelector, AggregatorSelector},
10
+ metrics::{controllers, processors},
13
11
  };
14
12
  use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
15
13
  use prometheus::{Encoder, TextEncoder};
16
- use std::{convert::Infallible, net::SocketAddr, sync::Arc};
14
+ use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
17
15
 
18
16
  /// Exposes prometheus metrics for scraping
19
17
  pub(super) struct PromServer {
20
- addr: SocketAddr,
18
+ bound_addr: AddrIncoming,
21
19
  pub exporter: Arc<PrometheusExporter>,
22
20
  }
23
21
 
24
22
  impl PromServer {
25
23
  pub fn new(
26
24
  addr: SocketAddr,
25
+ aggregation: impl AggregatorSelector + Send + Sync + 'static,
27
26
  temporality: impl TemporalitySelector + Send + Sync + 'static,
28
- ) -> Result<Self, MetricsError> {
27
+ ) -> Result<Self, anyhow::Error> {
29
28
  let controller =
30
- controllers::basic(processors::factory(SDKAggSelector, temporality).with_memory(true))
29
+ controllers::basic(processors::factory(aggregation, temporality).with_memory(true))
30
+ // Because Prom is pull-based, make this always refresh
31
+ .with_collect_period(Duration::from_secs(0))
31
32
  .with_resource(default_resource())
32
33
  .build();
33
34
  let exporter = ExporterBuilder::new(controller).try_init()?;
35
+ let bound_addr = AddrIncoming::bind(&addr)?;
34
36
  Ok(Self {
35
37
  exporter: Arc::new(exporter),
36
- addr,
38
+ bound_addr,
37
39
  })
38
40
  }
39
41
 
40
- pub async fn run(&self) -> hyper::Result<()> {
42
+ pub async fn run(self) -> hyper::Result<()> {
41
43
  // Spin up hyper server to serve metrics for scraping. We use hyper since we already depend
42
44
  // on it via Tonic.
43
45
  let expclone = self.exporter.clone();
@@ -45,9 +47,13 @@ impl PromServer {
45
47
  let expclone = expclone.clone();
46
48
  async move { Ok::<_, Infallible>(service_fn(move |req| metrics_req(req, expclone.clone()))) }
47
49
  });
48
- let server = Server::bind(&self.addr).serve(svc);
50
+ let server = Server::builder(self.bound_addr).serve(svc);
49
51
  server.await
50
52
  }
53
+
54
+ pub fn bound_addr(&self) -> SocketAddr {
55
+ self.bound_addr.local_addr()
56
+ }
51
57
  }
52
58
 
53
59
  /// Serves prometheus metrics in the expected format for scraping
@@ -5,12 +5,16 @@ use crate::{
5
5
  protosext::ValidPollWFTQResponse,
6
6
  replay::TestHistoryBuilder,
7
7
  sticky_q_name_for_worker,
8
+ telemetry::metrics::MetricsContext,
8
9
  worker::{
9
- client::{mocks::mock_workflow_client, MockWorkerClient, WorkerClient},
10
+ client::{
11
+ mocks::mock_workflow_client, MockWorkerClient, WorkerClient, WorkflowTaskCompletion,
12
+ },
10
13
  new_wft_poller,
11
14
  },
12
15
  TaskToken, Worker, WorkerConfig, WorkerConfigBuilder,
13
16
  };
17
+ use async_trait::async_trait;
14
18
  use bimap::BiMap;
15
19
  use futures::{future::BoxFuture, stream, stream::BoxStream, FutureExt, Stream, StreamExt};
16
20
  use mockall::TimesRange;
@@ -26,7 +30,7 @@ use std::{
26
30
  task::{Context, Poll},
27
31
  time::Duration,
28
32
  };
29
- use temporal_client::WorkflowTaskCompletion;
33
+ use temporal_sdk_core_api::errors::{PollActivityError, PollWfError};
30
34
  use temporal_sdk_core_api::Worker as WorkerTrait;
31
35
  use temporal_sdk_core_protos::{
32
36
  coresdk::{
@@ -50,13 +54,13 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
50
54
  use tokio_util::sync::CancellationToken;
51
55
 
52
56
  pub const TEST_Q: &str = "q";
53
- pub static NO_MORE_WORK_ERROR_MSG: &str = "No more work to do";
54
57
 
55
58
  pub fn test_worker_cfg() -> WorkerConfigBuilder {
56
59
  let mut wcb = WorkerConfigBuilder::default();
57
60
  wcb.namespace("default")
58
61
  .task_queue(TEST_Q)
59
62
  .worker_build_id("test_bin_id")
63
+ .ignore_evicts_on_shutdown(true)
60
64
  // Serial polling since it makes mocking much easier.
61
65
  .max_concurrent_wft_polls(1_usize);
62
66
  wcb
@@ -133,13 +137,19 @@ pub(crate) fn build_fake_worker(
133
137
 
134
138
  pub(crate) fn mock_worker(mocks: MocksHolder) -> Worker {
135
139
  let sticky_q = sticky_q_name_for_worker("unit-test", &mocks.inputs.config);
140
+ let act_poller = if mocks.inputs.config.no_remote_activities {
141
+ None
142
+ } else {
143
+ mocks.inputs.act_poller
144
+ };
136
145
  Worker::new_with_pollers(
137
146
  mocks.inputs.config,
138
147
  sticky_q,
139
148
  mocks.client,
140
149
  mocks.inputs.wft_stream,
141
- mocks.inputs.act_poller,
142
- Default::default(),
150
+ act_poller,
151
+ MetricsContext::no_op(),
152
+ None,
143
153
  CancellationToken::new(),
144
154
  )
145
155
  }
@@ -209,7 +219,7 @@ impl MockWorkerInputs {
209
219
  }
210
220
  pub fn new_from_poller(wf_poller: BoxedWFPoller) -> Self {
211
221
  Self {
212
- wft_stream: new_wft_poller(wf_poller, Default::default()).boxed(),
222
+ wft_stream: new_wft_poller(wf_poller, MetricsContext::no_op()).boxed(),
213
223
  act_poller: None,
214
224
  config: test_worker_cfg().build().unwrap(),
215
225
  }
@@ -293,7 +303,7 @@ where
293
303
  }
294
304
  .boxed()
295
305
  } else {
296
- async { Some(Err(tonic::Status::cancelled(NO_MORE_WORK_ERROR_MSG))) }.boxed()
306
+ async { None }.boxed()
297
307
  }
298
308
  });
299
309
  Box::new(mock_poller) as BoxedPoller<T>
@@ -367,10 +377,12 @@ pub(crate) struct MockPollCfg {
367
377
  pub expect_fail_wft_matcher:
368
378
  Box<dyn Fn(&TaskToken, &WorkflowTaskFailedCause, &Option<Failure>) -> bool + Send>,
369
379
  pub completion_asserts: Option<Box<dyn Fn(&WorkflowTaskCompletion) + Send>>,
380
+ pub num_expected_completions: Option<TimesRange>,
370
381
  /// If being used with the Rust SDK, this is set true. It ensures pollers will not error out
371
382
  /// early with no work, since we cannot know the exact number of times polling will happen.
372
383
  /// Instead, they will just block forever.
373
384
  pub using_rust_sdk: bool,
385
+ pub make_poll_stream_interminable: bool,
374
386
  }
375
387
 
376
388
  impl MockPollCfg {
@@ -387,7 +399,9 @@ impl MockPollCfg {
387
399
  mock_client: mock_workflow_client(),
388
400
  expect_fail_wft_matcher: Box::new(|_, _, _| true),
389
401
  completion_asserts: None,
402
+ num_expected_completions: None,
390
403
  using_rust_sdk: false,
404
+ make_poll_stream_interminable: false,
391
405
  }
392
406
  }
393
407
  pub fn from_resp_batches(
@@ -408,7 +422,9 @@ impl MockPollCfg {
408
422
  mock_client,
409
423
  expect_fail_wft_matcher: Box::new(|_, _, _| true),
410
424
  completion_asserts: None,
425
+ num_expected_completions: None,
411
426
  using_rust_sdk: false,
427
+ make_poll_stream_interminable: false,
412
428
  }
413
429
  }
414
430
  }
@@ -498,7 +514,7 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
498
514
  .into_iter()
499
515
  .map(|response| {
500
516
  let cur_attempt = attempts_at_task_num.entry(response.hashable()).or_insert(1);
501
- let mut r = hist_to_poll_resp(&hist.hist, hist.wf_id.clone(), response, TEST_Q);
517
+ let mut r = hist_to_poll_resp(&hist.hist, hist.wf_id.clone(), response);
502
518
  r.attempt = *cur_attempt;
503
519
  *cur_attempt += 1;
504
520
  r
@@ -576,16 +592,20 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
576
592
  );
577
593
 
578
594
  let outstanding = outstanding_wf_task_tokens.clone();
579
- cfg.mock_client
580
- .expect_complete_workflow_task()
581
- .returning(move |comp| {
582
- if let Some(ass) = cfg.completion_asserts.as_ref() {
583
- // tee hee
584
- ass(&comp)
585
- }
586
- outstanding.release_token(&comp.task_token);
587
- Ok(RespondWorkflowTaskCompletedResponse::default())
588
- });
595
+ let expect_completes = cfg.mock_client.expect_complete_workflow_task();
596
+ if let Some(range) = cfg.num_expected_completions {
597
+ expect_completes.times(range);
598
+ } else if cfg.completion_asserts.is_some() {
599
+ expect_completes.times(1..);
600
+ }
601
+ expect_completes.returning(move |comp| {
602
+ if let Some(ass) = cfg.completion_asserts.as_ref() {
603
+ // tee hee
604
+ ass(&comp)
605
+ }
606
+ outstanding.release_token(&comp.task_token);
607
+ Ok(RespondWorkflowTaskCompletedResponse::default())
608
+ });
589
609
  let outstanding = outstanding_wf_task_tokens.clone();
590
610
  cfg.mock_client
591
611
  .expect_fail_workflow_task()
@@ -604,11 +624,15 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
604
624
  Ok(Default::default())
605
625
  });
606
626
 
607
- MocksHolder {
627
+ let mut mh = MocksHolder {
608
628
  client: Arc::new(cfg.mock_client),
609
629
  inputs: mock_worker,
610
630
  outstanding_task_map: Some(outstanding_wf_task_tokens),
631
+ };
632
+ if cfg.make_poll_stream_interminable {
633
+ mh.make_wft_stream_interminable();
611
634
  }
635
+ mh
612
636
  }
613
637
 
614
638
  pub struct QueueResponse<T> {
@@ -649,7 +673,6 @@ pub fn hist_to_poll_resp(
649
673
  t: &TestHistoryBuilder,
650
674
  wf_id: impl Into<String>,
651
675
  response_type: ResponseType,
652
- task_queue: impl Into<String>,
653
676
  ) -> QueueResponse<PollWorkflowTaskQueueResponse> {
654
677
  let run_id = t.get_orig_run_id();
655
678
  let wf = WorkflowExecution {
@@ -678,7 +701,7 @@ pub fn hist_to_poll_resp(
678
701
  }
679
702
  }
680
703
  };
681
- let mut resp = hist_info.as_poll_wft_response(task_queue);
704
+ let mut resp = hist_info.as_poll_wft_response();
682
705
  resp.workflow_execution = Some(wf);
683
706
  QueueResponse { resp, delay_until }
684
707
  }
@@ -828,6 +851,7 @@ pub(crate) fn gen_assert_and_fail(asserter: &dyn Fn(&WorkflowActivation)) -> Ass
828
851
  message: "Intentional test failure".to_string(),
829
852
  ..Default::default()
830
853
  }),
854
+ ..Default::default()
831
855
  }
832
856
  .into(),
833
857
  )
@@ -873,3 +897,43 @@ macro_rules! prost_dur {
873
897
  .expect("test duration fits")
874
898
  };
875
899
  }
900
+
901
+ #[async_trait]
902
+ pub(crate) trait WorkerExt {
903
+ /// Initiate shutdown, drain the pollers, and wait for shutdown to complete.
904
+ async fn drain_pollers_and_shutdown(self);
905
+ /// Initiate shutdown, drain the *activity* poller, and wait for shutdown to complete.
906
+ /// Takes a ref because of that one test that needs it.
907
+ async fn drain_activity_poller_and_shutdown(&self);
908
+ }
909
+
910
+ #[async_trait]
911
+ impl WorkerExt for Worker {
912
+ async fn drain_pollers_and_shutdown(self) {
913
+ self.initiate_shutdown();
914
+ tokio::join!(
915
+ async {
916
+ assert_matches!(
917
+ self.poll_activity_task().await.unwrap_err(),
918
+ PollActivityError::ShutDown
919
+ );
920
+ },
921
+ async {
922
+ assert_matches!(
923
+ self.poll_workflow_activation().await.unwrap_err(),
924
+ PollWfError::ShutDown
925
+ );
926
+ }
927
+ );
928
+ self.finalize_shutdown().await;
929
+ }
930
+
931
+ async fn drain_activity_poller_and_shutdown(&self) {
932
+ self.initiate_shutdown();
933
+ assert_matches!(
934
+ self.poll_activity_task().await.unwrap_err(),
935
+ PollActivityError::ShutDown
936
+ );
937
+ self.shutdown().await;
938
+ }
939
+ }
@@ -26,9 +26,6 @@ use tokio_util::sync::CancellationToken;
26
26
  /// Used to supply new heartbeat events to the activity heartbeat manager, or to send a shutdown
27
27
  /// request.
28
28
  pub(crate) struct ActivityHeartbeatManager {
29
- /// Cancellations that have been received when heartbeating are queued here and can be consumed
30
- /// by [fetch_cancellations]
31
- incoming_cancels: Mutex<UnboundedReceiver<PendingActivityCancel>>,
32
29
  shutdown_token: CancellationToken,
33
30
  /// Used during `shutdown` to await until all inflight requests are sent.
34
31
  join_handle: Mutex<Option<JoinHandle<()>>>,
@@ -74,15 +71,118 @@ pub enum ActivityHeartbeatError {
74
71
  /// to heartbeat.
75
72
  #[error("Unable to parse activity heartbeat timeout.")]
76
73
  InvalidHeartbeatTimeout,
77
- /// Core is shutting down and thus new heartbeats are not accepted
78
- #[error("New heartbeat requests are not accepted while shutting down")]
79
- ShuttingDown,
80
74
  }
81
75
 
82
76
  /// Manages activity heartbeating for a worker. Allows sending new heartbeats or requesting and
83
77
  /// awaiting for the shutdown. When shutdown is requested, signal gets sent to all processors, which
84
78
  /// allows them to complete gracefully.
85
79
  impl ActivityHeartbeatManager {
80
+ /// Creates a new instance of an activity heartbeat manager and returns a handle to the user,
81
+ /// which allows to send new heartbeats and initiate the shutdown.
82
+ /// Returns the manager and a channel that buffers cancellation notifications to be sent to Lang.
83
+ pub(super) fn new(
84
+ client: Arc<dyn WorkerClient>,
85
+ ) -> (Self, UnboundedReceiver<PendingActivityCancel>) {
86
+ let (heartbeat_stream_state, heartbeat_tx_source, shutdown_token) =
87
+ HeartbeatStreamState::new();
88
+ let (cancels_tx, cancels_rx) = unbounded_channel();
89
+ let heartbeat_tx = heartbeat_tx_source.clone();
90
+
91
+ let join_handle = tokio::spawn(
92
+ // The stream of incoming heartbeats uses unfold to carry state across each item in the
93
+ // stream. The closure checks if, for any given activity, we should heartbeat or not
94
+ // depending on its delay and when we last issued a heartbeat for it.
95
+ futures::stream::unfold(heartbeat_stream_state, move |mut hb_states| {
96
+ async move {
97
+ let hb = tokio::select! {
98
+ biased;
99
+
100
+ _ = hb_states.cancellation_token.cancelled() => {
101
+ return None
102
+ }
103
+ hb = hb_states.incoming_hbs.recv() => match hb {
104
+ None => return None,
105
+ Some(hb) => hb,
106
+ }
107
+ };
108
+
109
+ Some((
110
+ match hb {
111
+ HeartbeatAction::SendHeartbeat(hb) => hb_states.record(hb),
112
+ HeartbeatAction::CompleteReport(tt) => hb_states.handle_report_completed(tt),
113
+ HeartbeatAction::CompleteThrottle(tt) => hb_states.handle_throttle_completed(tt),
114
+ HeartbeatAction::Evict{ token, on_complete } => hb_states.evict(token, on_complete),
115
+ },
116
+ hb_states,
117
+ ))
118
+ }
119
+ })
120
+ // Filters out `None`s
121
+ .filter_map(|opt| async { opt })
122
+ .for_each_concurrent(None, move |action| {
123
+ let heartbeat_tx = heartbeat_tx_source.clone();
124
+ let sg = client.clone();
125
+ let cancels_tx = cancels_tx.clone();
126
+ async move {
127
+ match action {
128
+ HeartbeatExecutorAction::Sleep(tt, duration, cancellation_token) => {
129
+ tokio::select! {
130
+ _ = cancellation_token.cancelled() => (),
131
+ _ = tokio::time::sleep(duration) => {
132
+ let _ = heartbeat_tx.send(HeartbeatAction::CompleteThrottle(tt));
133
+ },
134
+ };
135
+ }
136
+ HeartbeatExecutorAction::Report { task_token: tt, details } => {
137
+ match sg
138
+ .record_activity_heartbeat(tt.clone(), details.into_payloads())
139
+ .await
140
+ {
141
+ Ok(RecordActivityTaskHeartbeatResponse { cancel_requested }) => {
142
+ if cancel_requested {
143
+ cancels_tx
144
+ .send(PendingActivityCancel::new(
145
+ tt.clone(),
146
+ ActivityCancelReason::Cancelled,
147
+ ))
148
+ .expect(
149
+ "Receive half of heartbeat cancels not blocked",
150
+ );
151
+ }
152
+ }
153
+ // Send cancels for any activity that learns its workflow already
154
+ // finished (which is one thing not found implies - other reasons
155
+ // would seem equally valid).
156
+ Err(s) if s.code() == tonic::Code::NotFound => {
157
+ debug!(task_token = %tt,
158
+ "Activity not found when recording heartbeat");
159
+ cancels_tx
160
+ .send(PendingActivityCancel::new(
161
+ tt.clone(),
162
+ ActivityCancelReason::NotFound,
163
+ ))
164
+ .expect("Receive half of heartbeat cancels not blocked");
165
+ }
166
+ Err(e) => {
167
+ warn!("Error when recording heartbeat: {:?}", e);
168
+ }
169
+ };
170
+ let _ = heartbeat_tx.send(HeartbeatAction::CompleteReport(tt));
171
+ }
172
+ }
173
+ }
174
+ }),
175
+ );
176
+
177
+ (
178
+ Self {
179
+ join_handle: Mutex::new(Some(join_handle)),
180
+ shutdown_token,
181
+ heartbeat_tx,
182
+ },
183
+ cancels_rx,
184
+ )
185
+ }
86
186
  /// Records a new heartbeat, the first call will result in an immediate call to the server,
87
187
  /// while rapid successive calls would accumulate for up to `delay` and then latest heartbeat
88
188
  /// details will be sent to the server.
@@ -95,9 +195,6 @@ impl ActivityHeartbeatManager {
95
195
  hb: ActivityHeartbeat,
96
196
  throttle_interval: Duration,
97
197
  ) -> Result<(), ActivityHeartbeatError> {
98
- if self.shutdown_token.is_cancelled() {
99
- return Err(ActivityHeartbeatError::ShuttingDown);
100
- }
101
198
  self.heartbeat_tx
102
199
  .send(HeartbeatAction::SendHeartbeat(ValidActivityHeartbeat {
103
200
  task_token: TaskToken(hb.task_token),
@@ -121,13 +218,6 @@ impl ActivityHeartbeatManager {
121
218
  completed.notified().await;
122
219
  }
123
220
 
124
- /// Returns a future that resolves any time there is a new activity cancel that must be
125
- /// dispatched to lang
126
- pub(super) async fn next_pending_cancel(&self) -> Option<PendingActivityCancel> {
127
- self.incoming_cancels.lock().await.recv().await
128
- }
129
-
130
- // TODO: Can own self now!
131
221
  /// Initiates shutdown procedure by stopping lifecycle loop and awaiting for all in-flight
132
222
  /// heartbeat requests to be flushed to the server.
133
223
  pub(super) async fn shutdown(&self) {
@@ -301,110 +391,6 @@ impl HeartbeatStreamState {
301
391
  }
302
392
  }
303
393
 
304
- impl ActivityHeartbeatManager {
305
- /// Creates a new instance of an activity heartbeat manager and returns a handle to the user,
306
- /// which allows to send new heartbeats and initiate the shutdown.
307
- pub fn new(client: Arc<dyn WorkerClient>) -> Self {
308
- let (heartbeat_stream_state, heartbeat_tx_source, shutdown_token) =
309
- HeartbeatStreamState::new();
310
- let (cancels_tx, cancels_rx) = unbounded_channel();
311
- let heartbeat_tx = heartbeat_tx_source.clone();
312
-
313
- let join_handle = tokio::spawn(
314
- // The stream of incoming heartbeats uses unfold to carry state across each item in the
315
- // stream. The closure checks if, for any given activity, we should heartbeat or not
316
- // depending on its delay and when we last issued a heartbeat for it.
317
- futures::stream::unfold(heartbeat_stream_state, move |mut hb_states| {
318
- async move {
319
- let hb = tokio::select! {
320
- biased;
321
-
322
- _ = hb_states.cancellation_token.cancelled() => {
323
- return None
324
- }
325
- hb = hb_states.incoming_hbs.recv() => match hb {
326
- None => return None,
327
- Some(hb) => hb,
328
- }
329
- };
330
-
331
- Some((
332
- match hb {
333
- HeartbeatAction::SendHeartbeat(hb) => hb_states.record(hb),
334
- HeartbeatAction::CompleteReport(tt) => hb_states.handle_report_completed(tt),
335
- HeartbeatAction::CompleteThrottle(tt) => hb_states.handle_throttle_completed(tt),
336
- HeartbeatAction::Evict{ token, on_complete } => hb_states.evict(token, on_complete),
337
- },
338
- hb_states,
339
- ))
340
- }
341
- })
342
- // Filters out `None`s
343
- .filter_map(|opt| async { opt })
344
- .for_each_concurrent(None, move |action| {
345
- let heartbeat_tx = heartbeat_tx_source.clone();
346
- let sg = client.clone();
347
- let cancels_tx = cancels_tx.clone();
348
- async move {
349
- match action {
350
- HeartbeatExecutorAction::Sleep(tt, duration, cancellation_token) => {
351
- tokio::select! {
352
- _ = cancellation_token.cancelled() => (),
353
- _ = tokio::time::sleep(duration) => {
354
- let _ = heartbeat_tx.send(HeartbeatAction::CompleteThrottle(tt));
355
- },
356
- };
357
- }
358
- HeartbeatExecutorAction::Report { task_token: tt, details } => {
359
- match sg
360
- .record_activity_heartbeat(tt.clone(), details.into_payloads())
361
- .await
362
- {
363
- Ok(RecordActivityTaskHeartbeatResponse { cancel_requested }) => {
364
- if cancel_requested {
365
- cancels_tx
366
- .send(PendingActivityCancel::new(
367
- tt.clone(),
368
- ActivityCancelReason::Cancelled,
369
- ))
370
- .expect(
371
- "Receive half of heartbeat cancels not blocked",
372
- );
373
- }
374
- }
375
- // Send cancels for any activity that learns its workflow already
376
- // finished (which is one thing not found implies - other reasons
377
- // would seem equally valid).
378
- Err(s) if s.code() == tonic::Code::NotFound => {
379
- debug!(task_token = %tt,
380
- "Activity not found when recording heartbeat");
381
- cancels_tx
382
- .send(PendingActivityCancel::new(
383
- tt.clone(),
384
- ActivityCancelReason::NotFound,
385
- ))
386
- .expect("Receive half of heartbeat cancels not blocked");
387
- }
388
- Err(e) => {
389
- warn!("Error when recording heartbeat: {:?}", e);
390
- }
391
- };
392
- let _ = heartbeat_tx.send(HeartbeatAction::CompleteReport(tt));
393
- }
394
- }
395
- }
396
- }),
397
- );
398
-
399
- Self {
400
- incoming_cancels: Mutex::new(cancels_rx),
401
- join_handle: Mutex::new(Some(join_handle)),
402
- shutdown_token,
403
- heartbeat_tx,
404
- }
405
- }
406
- }
407
-
408
394
  #[cfg(test)]
409
395
  mod test {
410
396
  use super::*;
@@ -425,7 +411,7 @@ mod test {
425
411
  .expect_record_activity_heartbeat()
426
412
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
427
413
  .times(2);
428
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
414
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
429
415
  let fake_task_token = vec![1, 2, 3];
430
416
  // Send 2 heartbeat requests for 20ms apart.
431
417
  // The first heartbeat should be sent right away, and
@@ -446,14 +432,13 @@ mod test {
446
432
  .expect_record_activity_heartbeat()
447
433
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
448
434
  .times(3);
449
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
435
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
450
436
  let fake_task_token = vec![1, 2, 3];
451
437
  // Heartbeats always get sent if recorded less frequently than the throttle interval
452
438
  for i in 0_u8..3 {
453
439
  record_heartbeat(&hm, fake_task_token.clone(), i, Duration::from_millis(10));
454
440
  sleep(Duration::from_millis(20)).await;
455
441
  }
456
- // sleep again to let heartbeats be flushed
457
442
  hm.shutdown().await;
458
443
  }
459
444
 
@@ -466,7 +451,7 @@ mod test {
466
451
  .expect_record_activity_heartbeat()
467
452
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
468
453
  .times(1);
469
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
454
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
470
455
  let fake_task_token = vec![1, 2, 3];
471
456
  // Send a whole bunch of heartbeats very fast. We should still only send one total.
472
457
  for i in 0_u8..50 {
@@ -485,7 +470,7 @@ mod test {
485
470
  .expect_record_activity_heartbeat()
486
471
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
487
472
  .times(2);
488
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
473
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
489
474
  let fake_task_token = vec![1, 2, 3];
490
475
  record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
491
476
  sleep(Duration::from_millis(500)).await;
@@ -502,7 +487,7 @@ mod test {
502
487
  .expect_record_activity_heartbeat()
503
488
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
504
489
  .times(2);
505
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
490
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
506
491
  let fake_task_token = vec![1, 2, 3];
507
492
  record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
508
493
  // Let it propagate
@@ -522,42 +507,13 @@ mod test {
522
507
  .expect_record_activity_heartbeat()
523
508
  .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
524
509
  .times(1);
525
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
510
+ let (hm, _) = ActivityHeartbeatManager::new(Arc::new(mock_client));
526
511
  let fake_task_token = vec![1, 2, 3];
527
512
  record_heartbeat(&hm, fake_task_token.clone(), 0, Duration::from_millis(100));
528
513
  hm.evict(fake_task_token.clone().into()).await;
529
514
  hm.shutdown().await;
530
515
  }
531
516
 
532
- /// Recording new heartbeats after shutdown is not allowed, and will result in error.
533
- #[tokio::test]
534
- async fn record_after_shutdown() {
535
- let mut mock_client = mock_workflow_client();
536
- mock_client
537
- .expect_record_activity_heartbeat()
538
- .returning(|_, _| Ok(RecordActivityTaskHeartbeatResponse::default()))
539
- .times(0);
540
- let hm = ActivityHeartbeatManager::new(Arc::new(mock_client));
541
- hm.shutdown().await;
542
- match hm.record(
543
- ActivityHeartbeat {
544
- task_token: vec![1, 2, 3],
545
- details: vec![Payload {
546
- // payload doesn't matter in this case, as it shouldn't get sent anyways.
547
- ..Default::default()
548
- }],
549
- },
550
- Duration::from_millis(1000),
551
- ) {
552
- Ok(_) => {
553
- unreachable!("heartbeat should not be recorded after the shutdown");
554
- }
555
- Err(e) => {
556
- matches!(e, ActivityHeartbeatError::ShuttingDown);
557
- }
558
- }
559
- }
560
-
561
517
  fn record_heartbeat(
562
518
  hm: &ActivityHeartbeatManager,
563
519
  task_token: Vec<u8>,