temporalio 0.0.0 → 0.0.2

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 (327) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +301 -0
  3. data/bridge/Cargo.lock +2888 -0
  4. data/bridge/Cargo.toml +27 -0
  5. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  6. data/bridge/sdk-core/Cargo.lock +2606 -0
  7. data/bridge/sdk-core/Cargo.toml +2 -0
  8. data/bridge/sdk-core/LICENSE.txt +23 -0
  9. data/bridge/sdk-core/README.md +104 -0
  10. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  11. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  13. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  14. data/bridge/sdk-core/client/Cargo.toml +40 -0
  15. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  16. data/bridge/sdk-core/client/src/lib.rs +1286 -0
  17. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  18. data/bridge/sdk-core/client/src/raw.rs +932 -0
  19. data/bridge/sdk-core/client/src/retry.rs +751 -0
  20. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  21. data/bridge/sdk-core/core/Cargo.toml +116 -0
  22. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  23. data/bridge/sdk-core/core/benches/workflow_replay.rs +76 -0
  24. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  25. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -0
  26. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  27. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  28. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +925 -0
  29. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  30. data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -0
  31. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  32. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  33. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  34. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2090 -0
  35. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  36. data/bridge/sdk-core/core/src/lib.rs +282 -0
  37. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  38. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  39. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  40. data/bridge/sdk-core/core/src/replay/mod.rs +215 -0
  41. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  42. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  43. data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
  44. data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
  45. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
  46. data/bridge/sdk-core/core/src/test_help/mod.rs +889 -0
  47. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  48. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1048 -0
  49. data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
  50. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  51. data/bridge/sdk-core/core/src/worker/client.rs +373 -0
  52. data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
  53. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  54. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
  55. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
  60. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1200 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +655 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +985 -0
  80. data/bridge/sdk-core/core-api/Cargo.toml +32 -0
  81. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  82. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  83. data/bridge/sdk-core/core-api/src/lib.rs +109 -0
  84. data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
  85. data/bridge/sdk-core/core-api/src/worker.rs +148 -0
  86. data/bridge/sdk-core/etc/deps.svg +162 -0
  87. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  88. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  89. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  90. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  91. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  92. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  93. data/bridge/sdk-core/fsm/README.md +3 -0
  94. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  95. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  96. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  97. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  98. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  99. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  100. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  115. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  116. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  117. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  118. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  119. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  120. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  121. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  122. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  123. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  124. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  125. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  126. data/bridge/sdk-core/protos/api_upstream/buf.yaml +9 -0
  127. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  128. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  129. data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
  130. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  131. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  132. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +47 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +56 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +40 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +758 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +121 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +379 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -0
  164. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  165. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  166. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +263 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  174. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  175. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  176. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  179. data/bridge/sdk-core/rustfmt.toml +1 -0
  180. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  181. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  182. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  183. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  184. data/bridge/sdk-core/sdk/src/interceptors.rs +50 -0
  185. data/bridge/sdk-core/sdk/src/lib.rs +794 -0
  186. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  187. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  188. data/bridge/sdk-core/sdk/src/workflow_context.rs +694 -0
  189. data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -0
  190. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  191. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  192. data/bridge/sdk-core/sdk-core-protos/build.rs +107 -0
  193. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  194. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
  195. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  196. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  199. data/bridge/sdk-core/test-utils/Cargo.toml +36 -0
  200. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  201. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  202. data/bridge/sdk-core/test-utils/src/lib.rs +650 -0
  203. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  204. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  205. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +221 -0
  206. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  207. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -0
  208. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  209. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  210. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  211. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  212. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +788 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +223 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +597 -0
  227. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  228. data/bridge/sdk-core/tests/main.rs +113 -0
  229. data/bridge/sdk-core/tests/runner.rs +93 -0
  230. data/bridge/src/connection.rs +186 -0
  231. data/bridge/src/lib.rs +239 -0
  232. data/bridge/src/runtime.rs +54 -0
  233. data/bridge/src/worker.rs +124 -0
  234. data/ext/Rakefile +9 -0
  235. data/lib/bridge.so +0 -0
  236. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  237. data/lib/gen/temporal/api/batch/v1/message_pb.rb +50 -0
  238. data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
  239. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  240. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
  241. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
  242. data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
  243. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
  244. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
  245. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -0
  246. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  247. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  248. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  249. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  250. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  251. data/lib/gen/temporal/api/enums/v1/update_pb.rb +23 -0
  252. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  253. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  254. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  255. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  256. data/lib/gen/temporal/api/history/v1/message_pb.rb +490 -0
  257. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
  258. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  259. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -0
  260. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  261. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  262. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  263. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +149 -0
  264. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  265. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  266. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
  267. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -0
  268. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  269. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  270. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  271. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  272. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  273. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  274. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  275. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  276. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +165 -0
  277. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
  278. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  279. data/lib/temporalio/activity/context.rb +97 -0
  280. data/lib/temporalio/activity/info.rb +67 -0
  281. data/lib/temporalio/activity.rb +85 -0
  282. data/lib/temporalio/bridge/error.rb +8 -0
  283. data/lib/temporalio/bridge.rb +14 -0
  284. data/lib/temporalio/client/implementation.rb +340 -0
  285. data/lib/temporalio/client/workflow_handle.rb +243 -0
  286. data/lib/temporalio/client.rb +131 -0
  287. data/lib/temporalio/connection.rb +751 -0
  288. data/lib/temporalio/data_converter.rb +191 -0
  289. data/lib/temporalio/error/failure.rb +194 -0
  290. data/lib/temporalio/error/workflow_failure.rb +19 -0
  291. data/lib/temporalio/errors.rb +40 -0
  292. data/lib/temporalio/failure_converter/base.rb +26 -0
  293. data/lib/temporalio/failure_converter/basic.rb +319 -0
  294. data/lib/temporalio/failure_converter.rb +7 -0
  295. data/lib/temporalio/interceptor/chain.rb +28 -0
  296. data/lib/temporalio/interceptor/client.rb +123 -0
  297. data/lib/temporalio/payload_codec/base.rb +32 -0
  298. data/lib/temporalio/payload_converter/base.rb +24 -0
  299. data/lib/temporalio/payload_converter/bytes.rb +27 -0
  300. data/lib/temporalio/payload_converter/composite.rb +49 -0
  301. data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
  302. data/lib/temporalio/payload_converter/json.rb +26 -0
  303. data/lib/temporalio/payload_converter/nil.rb +26 -0
  304. data/lib/temporalio/payload_converter.rb +14 -0
  305. data/lib/temporalio/retry_policy.rb +82 -0
  306. data/lib/temporalio/retry_state.rb +35 -0
  307. data/lib/temporalio/runtime.rb +25 -0
  308. data/lib/temporalio/timeout_type.rb +29 -0
  309. data/lib/temporalio/version.rb +3 -0
  310. data/lib/temporalio/worker/activity_runner.rb +92 -0
  311. data/lib/temporalio/worker/activity_worker.rb +138 -0
  312. data/lib/temporalio/worker/reactor.rb +46 -0
  313. data/lib/temporalio/worker/runner.rb +63 -0
  314. data/lib/temporalio/worker/sync_worker.rb +88 -0
  315. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  316. data/lib/temporalio/worker.rb +198 -0
  317. data/lib/temporalio/workflow/execution_info.rb +54 -0
  318. data/lib/temporalio/workflow/execution_status.rb +36 -0
  319. data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
  320. data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
  321. data/lib/temporalio.rb +12 -1
  322. data/lib/thermite_patch.rb +23 -0
  323. data/temporalio.gemspec +45 -0
  324. metadata +566 -9
  325. data/lib/temporal/version.rb +0 -3
  326. data/lib/temporal.rb +0 -4
  327. data/temporal.gemspec +0 -20
@@ -0,0 +1,481 @@
1
+ mod activity_heartbeat_manager;
2
+ mod local_activities;
3
+
4
+ pub(crate) use local_activities::{
5
+ DispatchOrTimeoutLA, ExecutingLAId, LACompleteAction, LocalActRequest,
6
+ LocalActivityExecutionResult, LocalActivityManager, LocalActivityResolution,
7
+ LocalInFlightActInfo, NewLocalAct,
8
+ };
9
+
10
+ use crate::telemetry::metrics::eager;
11
+ use crate::{
12
+ abstractions::{MeteredSemaphore, OwnedMeteredSemPermit},
13
+ pollers::BoxedActPoller,
14
+ telemetry::metrics::{activity_type, activity_worker_type, workflow_type, MetricsContext},
15
+ worker::{
16
+ activities::activity_heartbeat_manager::ActivityHeartbeatError, client::WorkerClient,
17
+ },
18
+ PollActivityError, TaskToken,
19
+ };
20
+ use activity_heartbeat_manager::ActivityHeartbeatManager;
21
+ use dashmap::DashMap;
22
+ use governor::{
23
+ clock::DefaultClock,
24
+ middleware::NoOpMiddleware,
25
+ state::{InMemoryState, NotKeyed},
26
+ Quota, RateLimiter,
27
+ };
28
+ use std::{
29
+ convert::TryInto,
30
+ sync::Arc,
31
+ time::{Duration, Instant},
32
+ };
33
+ use temporal_sdk_core_protos::{
34
+ coresdk::{
35
+ activity_result::{self as ar, activity_execution_result as aer},
36
+ activity_task::{ActivityCancelReason, ActivityTask},
37
+ ActivityHeartbeat,
38
+ },
39
+ temporal::api::{
40
+ failure::v1::{failure::FailureInfo, CanceledFailureInfo, Failure},
41
+ workflowservice::v1::PollActivityTaskQueueResponse,
42
+ },
43
+ };
44
+ use tokio::sync::Notify;
45
+ use tracing::Span;
46
+
47
+ #[derive(Debug, derive_more::Constructor)]
48
+ struct PendingActivityCancel {
49
+ task_token: TaskToken,
50
+ reason: ActivityCancelReason,
51
+ }
52
+
53
+ /// Contains details that core wants to store while an activity is running.
54
+ #[derive(Debug)]
55
+ struct InFlightActInfo {
56
+ pub activity_type: String,
57
+ pub workflow_type: String,
58
+ /// Only kept for logging reasons
59
+ pub workflow_id: String,
60
+ /// Only kept for logging reasons
61
+ pub workflow_run_id: String,
62
+ start_time: Instant,
63
+ }
64
+
65
+ /// Augments [InFlightActInfo] with details specific to remote activities
66
+ struct RemoteInFlightActInfo {
67
+ pub base: InFlightActInfo,
68
+ /// Used to calculate aggregation delay between activity heartbeats.
69
+ pub heartbeat_timeout: Option<prost_types::Duration>,
70
+ /// Set to true if we have already issued a cancellation activation to lang for this activity
71
+ pub issued_cancel_to_lang: bool,
72
+ /// Set to true if we have already learned from the server this activity doesn't exist. EX:
73
+ /// we have learned from heartbeating and issued a cancel task, in which case we may simply
74
+ /// discard the reply.
75
+ pub known_not_found: bool,
76
+ /// The permit from the max concurrent semaphore
77
+ _permit: OwnedMeteredSemPermit,
78
+ }
79
+ impl RemoteInFlightActInfo {
80
+ fn new(poll_resp: &PollActivityTaskQueueResponse, permit: OwnedMeteredSemPermit) -> Self {
81
+ let wec = poll_resp.workflow_execution.clone().unwrap_or_default();
82
+ Self {
83
+ base: InFlightActInfo {
84
+ activity_type: poll_resp.activity_type.clone().unwrap_or_default().name,
85
+ workflow_type: poll_resp.workflow_type.clone().unwrap_or_default().name,
86
+ workflow_id: wec.workflow_id,
87
+ workflow_run_id: wec.run_id,
88
+ start_time: Instant::now(),
89
+ },
90
+ heartbeat_timeout: poll_resp.heartbeat_timeout.clone(),
91
+ issued_cancel_to_lang: false,
92
+ known_not_found: false,
93
+ _permit: permit,
94
+ }
95
+ }
96
+ }
97
+
98
+ struct NonPollActBuffer {
99
+ tx: async_channel::Sender<PermittedTqResp>,
100
+ rx: async_channel::Receiver<PermittedTqResp>,
101
+ }
102
+ impl NonPollActBuffer {
103
+ pub fn new() -> Self {
104
+ let (tx, rx) = async_channel::unbounded();
105
+ Self { tx, rx }
106
+ }
107
+
108
+ pub async fn next(&self) -> PermittedTqResp {
109
+ self.rx.recv().await.expect("Send half cannot be dropped")
110
+ }
111
+ }
112
+
113
+ pub(crate) struct WorkerActivityTasks {
114
+ /// Centralizes management of heartbeat issuing / throttling
115
+ heartbeat_manager: ActivityHeartbeatManager,
116
+ /// Activities that have been issued to lang but not yet completed
117
+ outstanding_activity_tasks: DashMap<TaskToken, RemoteInFlightActInfo>,
118
+ /// Buffers activity task polling in the event we need to return a cancellation while a poll is
119
+ /// ongoing.
120
+ poller: BoxedActPoller,
121
+ /// Holds activity tasks we have received by non-polling means. EX: In direct response to
122
+ /// workflow task completion.
123
+ non_poll_tasks: NonPollActBuffer,
124
+ /// Ensures we stay at or below this worker's maximum concurrent activity limit
125
+ activities_semaphore: Arc<MeteredSemaphore>,
126
+ /// Enables per-worker rate-limiting of activity tasks
127
+ ratelimiter: Option<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>,
128
+ /// Wakes every time an activity is removed from the outstanding map
129
+ complete_notify: Notify,
130
+
131
+ metrics: MetricsContext,
132
+
133
+ max_heartbeat_throttle_interval: Duration,
134
+ default_heartbeat_throttle_interval: Duration,
135
+ }
136
+
137
+ impl WorkerActivityTasks {
138
+ pub(crate) fn new(
139
+ max_activity_tasks: usize,
140
+ max_worker_act_per_sec: Option<f64>,
141
+ poller: BoxedActPoller,
142
+ client: Arc<dyn WorkerClient>,
143
+ metrics: MetricsContext,
144
+ max_heartbeat_throttle_interval: Duration,
145
+ default_heartbeat_throttle_interval: Duration,
146
+ ) -> Self {
147
+ Self {
148
+ heartbeat_manager: ActivityHeartbeatManager::new(client),
149
+ outstanding_activity_tasks: Default::default(),
150
+ poller,
151
+ non_poll_tasks: NonPollActBuffer::new(),
152
+ activities_semaphore: Arc::new(MeteredSemaphore::new(
153
+ max_activity_tasks,
154
+ metrics.with_new_attrs([activity_worker_type()]),
155
+ MetricsContext::available_task_slots,
156
+ )),
157
+ ratelimiter: max_worker_act_per_sec.and_then(|ps| {
158
+ Quota::with_period(Duration::from_secs_f64(ps.recip())).map(RateLimiter::direct)
159
+ }),
160
+ complete_notify: Notify::new(),
161
+ metrics,
162
+ max_heartbeat_throttle_interval,
163
+ default_heartbeat_throttle_interval,
164
+ }
165
+ }
166
+
167
+ pub(crate) fn notify_shutdown(&self) {
168
+ self.poller.notify_shutdown();
169
+ }
170
+
171
+ /// Wait for all outstanding activity tasks to finish
172
+ pub(crate) async fn wait_all_finished(&self) {
173
+ while !self.outstanding_activity_tasks.is_empty() {
174
+ self.complete_notify.notified().await
175
+ }
176
+ }
177
+
178
+ pub(crate) async fn shutdown(self) {
179
+ self.poller.shutdown_box().await;
180
+ self.heartbeat_manager.shutdown().await;
181
+ }
182
+
183
+ /// Wait until not at the outstanding activity limit, and then poll for an activity task.
184
+ ///
185
+ /// Returns `Ok(None)` if no activity is ready and the overall polling loop should be retried.
186
+ pub(crate) async fn poll(&self) -> Result<Option<ActivityTask>, PollActivityError> {
187
+ let poll_with_semaphore = async {
188
+ // Acquire and subsequently forget a permit for an outstanding activity. When they are
189
+ // completed, we must add a new permit to the semaphore, since holding the permit the
190
+ // entire time lang does work would be a challenge.
191
+ let perm = self
192
+ .activities_semaphore
193
+ .acquire_owned()
194
+ .await
195
+ .expect("outstanding activity semaphore not closed");
196
+ if let Some(ref rl) = self.ratelimiter {
197
+ rl.until_ready().await;
198
+ }
199
+ (self.poller.poll().await, perm)
200
+ };
201
+
202
+ tokio::select! {
203
+ biased;
204
+
205
+ cancel_task = self.next_pending_cancel_task() => {
206
+ cancel_task
207
+ }
208
+ task = self.non_poll_tasks.next() => {
209
+ Ok(Some(self.about_to_issue_task(task, true)))
210
+ }
211
+ (work, permit) = poll_with_semaphore => {
212
+ match work {
213
+ Some(Ok(work)) => {
214
+ if work == PollActivityTaskQueueResponse::default() {
215
+ // Timeout
216
+ self.metrics.act_poll_timeout();
217
+ return Ok(None)
218
+ }
219
+ let work = self.about_to_issue_task(PermittedTqResp {
220
+ resp: work, permit
221
+ }, false);
222
+ Ok(Some(work))
223
+ }
224
+ None => {
225
+ Err(PollActivityError::ShutDown)
226
+ }
227
+ Some(Err(e)) => Err(e.into())
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ pub(crate) async fn complete(
234
+ &self,
235
+ task_token: TaskToken,
236
+ status: aer::Status,
237
+ client: &dyn WorkerClient,
238
+ ) {
239
+ if let Some((_, act_info)) = self.outstanding_activity_tasks.remove(&task_token) {
240
+ let act_metrics = self.metrics.with_new_attrs([
241
+ activity_type(act_info.base.activity_type),
242
+ workflow_type(act_info.base.workflow_type),
243
+ ]);
244
+ Span::current().record("workflow_id", act_info.base.workflow_id);
245
+ Span::current().record("run_id", act_info.base.workflow_run_id);
246
+ act_metrics.act_execution_latency(act_info.base.start_time.elapsed());
247
+ let known_not_found = act_info.known_not_found;
248
+
249
+ self.heartbeat_manager.evict(task_token.clone()).await;
250
+ self.complete_notify.notify_waiters();
251
+
252
+ // No need to report activities which we already know the server doesn't care about
253
+ if !known_not_found {
254
+ let maybe_net_err = match status {
255
+ aer::Status::WillCompleteAsync(_) => None,
256
+ aer::Status::Completed(ar::Success { result }) => client
257
+ .complete_activity_task(task_token.clone(), result.map(Into::into))
258
+ .await
259
+ .err(),
260
+ aer::Status::Failed(ar::Failure { failure }) => {
261
+ act_metrics.act_execution_failed();
262
+ client
263
+ .fail_activity_task(task_token.clone(), failure.map(Into::into))
264
+ .await
265
+ .err()
266
+ }
267
+ aer::Status::Cancelled(ar::Cancellation { failure }) => {
268
+ let details = if let Some(Failure {
269
+ failure_info:
270
+ Some(FailureInfo::CanceledFailureInfo(CanceledFailureInfo { details })),
271
+ ..
272
+ }) = failure
273
+ {
274
+ details
275
+ } else {
276
+ warn!(task_token = ? task_token,
277
+ "Expected activity cancelled status with CanceledFailureInfo");
278
+ None
279
+ };
280
+ client
281
+ .cancel_activity_task(task_token.clone(), details.map(Into::into))
282
+ .await
283
+ .err()
284
+ }
285
+ };
286
+
287
+ if let Some(e) = maybe_net_err {
288
+ if e.code() == tonic::Code::NotFound {
289
+ warn!(task_token = ?task_token, details = ?e, "Activity not found on \
290
+ completion. This may happen if the activity has already been cancelled but \
291
+ completed anyway.");
292
+ } else {
293
+ warn!(error=?e, "Network error while completing activity");
294
+ };
295
+ };
296
+ };
297
+ } else {
298
+ warn!(
299
+ "Attempted to complete activity task {} but we were not tracking it",
300
+ &task_token
301
+ );
302
+ }
303
+ }
304
+
305
+ /// Attempt to record an activity heartbeat
306
+ pub(crate) fn record_heartbeat(
307
+ &self,
308
+ details: ActivityHeartbeat,
309
+ ) -> Result<(), ActivityHeartbeatError> {
310
+ // TODO: Propagate these back as cancels. Silent fails is too nonobvious
311
+ let heartbeat_timeout: Duration = self
312
+ .outstanding_activity_tasks
313
+ .get(&TaskToken(details.task_token.clone()))
314
+ .ok_or(ActivityHeartbeatError::UnknownActivity)?
315
+ .heartbeat_timeout
316
+ .clone()
317
+ // We treat None as 0 (even though heartbeat_timeout is never set to None by the server)
318
+ .unwrap_or_default()
319
+ .try_into()
320
+ // This technically should never happen since prost duration should be directly mappable
321
+ // to std::time::Duration.
322
+ .or(Err(ActivityHeartbeatError::InvalidHeartbeatTimeout))?;
323
+
324
+ // There is a bug in the server that translates non-set heartbeat timeouts into 0 duration.
325
+ // That's why we treat 0 the same way as None, otherwise we wouldn't know which aggregation
326
+ // delay to use, and using 0 is not a good idea as SDK would hammer the server too hard.
327
+ let throttle_interval = if heartbeat_timeout.as_millis() == 0 {
328
+ self.default_heartbeat_throttle_interval
329
+ } else {
330
+ heartbeat_timeout.mul_f64(0.8)
331
+ };
332
+ let throttle_interval =
333
+ std::cmp::min(throttle_interval, self.max_heartbeat_throttle_interval);
334
+ self.heartbeat_manager.record(details, throttle_interval)
335
+ }
336
+
337
+ /// Returns a handle that the workflows management side can use to interact with this manager
338
+ pub(crate) fn get_handle_for_workflows(&self) -> ActivitiesFromWFTsHandle {
339
+ ActivitiesFromWFTsHandle {
340
+ sem: self.activities_semaphore.clone(),
341
+ tx: self.non_poll_tasks.tx.clone(),
342
+ }
343
+ }
344
+
345
+ async fn next_pending_cancel_task(&self) -> Result<Option<ActivityTask>, PollActivityError> {
346
+ let next_pc = self.heartbeat_manager.next_pending_cancel().await;
347
+ // Issue cancellations for anything we noticed was cancelled during heartbeating
348
+ if let Some(PendingActivityCancel { task_token, reason }) = next_pc {
349
+ // It's possible that activity has been completed and we no longer have an
350
+ // outstanding activity task. This is fine because it means that we no
351
+ // longer need to cancel this activity, so we'll just ignore such orphaned
352
+ // cancellations.
353
+ if let Some(mut details) = self.outstanding_activity_tasks.get_mut(&task_token) {
354
+ if details.issued_cancel_to_lang {
355
+ // Don't double-issue cancellations
356
+ return Ok(None);
357
+ }
358
+
359
+ details.issued_cancel_to_lang = true;
360
+ if reason == ActivityCancelReason::NotFound {
361
+ details.known_not_found = true;
362
+ }
363
+ Ok(Some(ActivityTask::cancel_from_ids(task_token.0, reason)))
364
+ } else {
365
+ debug!(task_token = ?task_token, "Unknown activity task when issuing cancel");
366
+ // If we can't find the activity here, it's already been completed,
367
+ // in which case issuing a cancel again is pointless.
368
+ Ok(None)
369
+ }
370
+ } else {
371
+ // The only situation where the next cancel would return none is if the manager
372
+ // was dropped, which can only happen on shutdown.
373
+ Err(PollActivityError::ShutDown)
374
+ }
375
+ }
376
+
377
+ /// Called when there is a new act task about to be bubbled up out of the manager
378
+ fn about_to_issue_task(&self, task: PermittedTqResp, is_eager: bool) -> ActivityTask {
379
+ if let Some(ref act_type) = task.resp.activity_type {
380
+ if let Some(ref wf_type) = task.resp.workflow_type {
381
+ self.metrics
382
+ .with_new_attrs([
383
+ activity_type(act_type.name.clone()),
384
+ workflow_type(wf_type.name.clone()),
385
+ eager(is_eager),
386
+ ])
387
+ .act_task_received();
388
+ }
389
+ }
390
+ // There could be an else statement here but since the response should always contain both
391
+ // activity_type and workflow_type, we won't bother.
392
+
393
+ if let Some(dur) = task.resp.sched_to_start() {
394
+ self.metrics.act_sched_to_start_latency(dur);
395
+ };
396
+
397
+ self.outstanding_activity_tasks.insert(
398
+ task.resp.task_token.clone().into(),
399
+ RemoteInFlightActInfo::new(&task.resp, task.permit),
400
+ );
401
+
402
+ ActivityTask::start_from_poll_resp(task.resp)
403
+ }
404
+
405
+ #[cfg(test)]
406
+ pub(crate) fn remaining_activity_capacity(&self) -> usize {
407
+ self.activities_semaphore.available_permits()
408
+ }
409
+ }
410
+
411
+ /// Provides facilities for the workflow side of things to interact with the activity manager.
412
+ /// Allows for the handling of activities returned by WFT completions.
413
+ pub(crate) struct ActivitiesFromWFTsHandle {
414
+ sem: Arc<MeteredSemaphore>,
415
+ tx: async_channel::Sender<PermittedTqResp>,
416
+ }
417
+
418
+ impl ActivitiesFromWFTsHandle {
419
+ /// Returns a handle that can be used to reserve an activity slot. EX: When requesting eager
420
+ /// dispatch of an activity to this worker upon workflow task completion
421
+ pub(crate) fn reserve_slot(&self) -> Option<OwnedMeteredSemPermit> {
422
+ self.sem.try_acquire_owned().ok()
423
+ }
424
+
425
+ /// Queue new activity tasks for dispatch received from non-polling sources (ex: eager returns
426
+ /// from WFT completion)
427
+ pub(crate) fn add_tasks(&self, tasks: impl IntoIterator<Item = PermittedTqResp>) {
428
+ for t in tasks.into_iter() {
429
+ // Technically we should be reporting `activity_task_received` here, but for simplicity
430
+ // and time insensitivity, that metric is tracked in `about_to_issue_task`.
431
+ self.tx.try_send(t).expect("Receive half cannot be dropped");
432
+ }
433
+ }
434
+ }
435
+
436
+ pub(crate) struct PermittedTqResp {
437
+ pub permit: OwnedMeteredSemPermit,
438
+ pub resp: PollActivityTaskQueueResponse,
439
+ }
440
+
441
+ #[cfg(test)]
442
+ mod tests {
443
+ use super::*;
444
+ use crate::{
445
+ test_help::mock_poller_from_resps, worker::client::mocks::mock_manual_workflow_client,
446
+ };
447
+
448
+ #[tokio::test]
449
+ async fn per_worker_ratelimit() {
450
+ let poller = mock_poller_from_resps([
451
+ PollActivityTaskQueueResponse {
452
+ task_token: vec![1],
453
+ activity_id: "act1".to_string(),
454
+ ..Default::default()
455
+ }
456
+ .into(),
457
+ PollActivityTaskQueueResponse {
458
+ task_token: vec![2],
459
+ activity_id: "act2".to_string(),
460
+ ..Default::default()
461
+ }
462
+ .into(),
463
+ ]);
464
+ let atm = WorkerActivityTasks::new(
465
+ 10,
466
+ Some(2.0),
467
+ poller,
468
+ Arc::new(mock_manual_workflow_client()),
469
+ MetricsContext::no_op(),
470
+ Duration::from_secs(1),
471
+ Duration::from_secs(1),
472
+ );
473
+ let start = Instant::now();
474
+ atm.poll().await.unwrap().unwrap();
475
+ atm.poll().await.unwrap().unwrap();
476
+ // At least half a second will have elapsed since we only allow 2 tasks per second.
477
+ // With no ratelimit, even on a slow CI server with lots of load, this would typically take
478
+ // low single digit ms or less.
479
+ assert!(start.elapsed() > Duration::from_secs_f64(0.5));
480
+ }
481
+ }
@@ -0,0 +1,87 @@
1
+ use super::*;
2
+ use futures::Future;
3
+
4
+ #[cfg(test)]
5
+ /// Create a mock client primed with basic necessary expectations
6
+ pub(crate) fn mock_workflow_client() -> MockWorkerClient {
7
+ MockWorkerClient::new()
8
+ }
9
+
10
+ /// Create a mock manual client primed with basic necessary expectations
11
+ pub(crate) fn mock_manual_workflow_client() -> MockManualWorkerClient {
12
+ MockManualWorkerClient::new()
13
+ }
14
+
15
+ // Need a version of the mock that can return futures so we can return potentially pending
16
+ // results. This is really annoying b/c of the async trait stuff. Need
17
+ // https://github.com/asomers/mockall/issues/189 to be fixed for it to go away.
18
+ mockall::mock! {
19
+ pub(crate) ManualWorkerClient {}
20
+ #[allow(unused)]
21
+ impl WorkerClient for ManualWorkerClient {
22
+ fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String, is_sticky: bool)
23
+ -> impl Future<Output = Result<PollWorkflowTaskQueueResponse>> + Send + 'b
24
+ where 'a: 'b, Self: 'b;
25
+
26
+ fn poll_activity_task<'a, 'b>(&self, task_queue: String, max_tasks_per_sec: Option<f64>)
27
+ -> impl Future<Output = Result<PollActivityTaskQueueResponse>> + Send + 'b
28
+ where 'a: 'b, Self: 'b;
29
+
30
+ fn complete_workflow_task<'a, 'b>(
31
+ &self,
32
+ request: WorkflowTaskCompletion,
33
+ ) -> impl Future<Output = Result<RespondWorkflowTaskCompletedResponse>> + Send + 'b
34
+ where 'a: 'b, Self: 'b;
35
+
36
+ fn complete_activity_task<'a, 'b>(
37
+ &self,
38
+ task_token: TaskToken,
39
+ result: Option<Payloads>,
40
+ ) -> impl Future<Output = Result<RespondActivityTaskCompletedResponse>> + Send + 'b
41
+ where 'a: 'b, Self: 'b;
42
+
43
+ fn cancel_activity_task<'a, 'b>(
44
+ &self,
45
+ task_token: TaskToken,
46
+ details: Option<Payloads>,
47
+ ) -> impl Future<Output = Result<RespondActivityTaskCanceledResponse>> + Send + 'b
48
+ where 'a: 'b, Self: 'b;
49
+
50
+ fn fail_activity_task<'a, 'b>(
51
+ &self,
52
+ task_token: TaskToken,
53
+ failure: Option<Failure>,
54
+ ) -> impl Future<Output = Result<RespondActivityTaskFailedResponse>> + Send + 'b
55
+ where 'a: 'b, Self: 'b;
56
+
57
+ fn fail_workflow_task<'a, 'b>(
58
+ &self,
59
+ task_token: TaskToken,
60
+ cause: WorkflowTaskFailedCause,
61
+ failure: Option<Failure>,
62
+ ) -> impl Future<Output = Result<RespondWorkflowTaskFailedResponse>> + Send + 'b
63
+ where 'a: 'b, Self: 'b;
64
+
65
+ fn record_activity_heartbeat<'a, 'b>(
66
+ &self,
67
+ task_token: TaskToken,
68
+ details: Option<Payloads>,
69
+ ) -> impl Future<Output = Result<RecordActivityTaskHeartbeatResponse>> + Send + 'b
70
+ where 'a: 'b, Self: 'b;
71
+
72
+ fn get_workflow_execution_history<'a, 'b>(
73
+ &self,
74
+ workflow_id: String,
75
+ run_id: Option<String>,
76
+ page_token: Vec<u8>
77
+ ) -> impl Future<Output = Result<GetWorkflowExecutionHistoryResponse>> + Send + 'b
78
+ where 'a: 'b, Self: 'b;
79
+
80
+ fn respond_legacy_query<'a, 'b>(
81
+ &self,
82
+ task_token: TaskToken,
83
+ query_result: QueryResult,
84
+ ) -> impl Future<Output = Result<RespondQueryTaskCompletedResponse>> + Send + 'b
85
+ where 'a: 'b, Self: 'b;
86
+ }
87
+ }