temporalio 0.0.0 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,1200 @@
1
+ //! This module and its submodules implement Core's logic for managing workflows (which is the
2
+ //! lion's share of the complexity in Core). See the `ARCHITECTURE.md` file in the repo root for
3
+ //! a diagram of the internals.
4
+
5
+ mod bridge;
6
+ mod driven_workflow;
7
+ mod history_update;
8
+ mod machines;
9
+ mod managed_run;
10
+ mod run_cache;
11
+ pub(crate) mod wft_poller;
12
+ mod workflow_stream;
13
+
14
+ pub(crate) use bridge::WorkflowBridge;
15
+ pub(crate) use driven_workflow::{DrivenWorkflow, WorkflowFetcher};
16
+ pub(crate) use history_update::{HistoryPaginator, HistoryUpdate};
17
+ pub(crate) use machines::WFMachinesError;
18
+ #[cfg(test)]
19
+ pub(crate) use managed_run::ManagedWFFunc;
20
+
21
+ use crate::{
22
+ abstractions::OwnedMeteredSemPermit,
23
+ protosext::{legacy_query_failure, ValidPollWFTQResponse, WorkflowActivationExt},
24
+ telemetry::VecDisplayer,
25
+ worker::{
26
+ activities::{ActivitiesFromWFTsHandle, PermittedTqResp},
27
+ client::{WorkerClient, WorkflowTaskCompletion},
28
+ workflow::{
29
+ managed_run::{ManagedRun, WorkflowManager},
30
+ wft_poller::validate_wft,
31
+ workflow_stream::{LocalInput, LocalInputs, WFStream},
32
+ },
33
+ LocalActRequest, LocalActivityResolution,
34
+ },
35
+ MetricsContext,
36
+ };
37
+ use futures::{stream::BoxStream, Stream, StreamExt};
38
+ use std::{
39
+ collections::HashSet,
40
+ fmt::{Debug, Display, Formatter},
41
+ future::Future,
42
+ ops::DerefMut,
43
+ result,
44
+ sync::Arc,
45
+ time::{Duration, Instant},
46
+ };
47
+ use temporal_sdk_core_api::errors::{CompleteWfError, PollWfError};
48
+ use temporal_sdk_core_protos::{
49
+ coresdk::{
50
+ workflow_activation::{
51
+ remove_from_cache::EvictionReason, workflow_activation_job, QueryWorkflow,
52
+ WorkflowActivation, WorkflowActivationJob,
53
+ },
54
+ workflow_commands::*,
55
+ workflow_completion,
56
+ workflow_completion::{
57
+ workflow_activation_completion, Failure, WorkflowActivationCompletion,
58
+ },
59
+ },
60
+ temporal::api::{
61
+ command::v1::{command::Attributes, Command as ProtoCommand, Command},
62
+ common::v1::{Memo, RetryPolicy, SearchAttributes},
63
+ enums::v1::WorkflowTaskFailedCause,
64
+ taskqueue::v1::StickyExecutionAttributes,
65
+ workflowservice::v1::PollActivityTaskQueueResponse,
66
+ },
67
+ TaskToken,
68
+ };
69
+ use tokio::{
70
+ sync::{
71
+ mpsc::{unbounded_channel, UnboundedSender},
72
+ oneshot,
73
+ },
74
+ task,
75
+ task::{JoinError, JoinHandle},
76
+ };
77
+ use tokio_stream::wrappers::UnboundedReceiverStream;
78
+ use tokio_util::sync::CancellationToken;
79
+ use tracing::Span;
80
+
81
+ pub(crate) const LEGACY_QUERY_ID: &str = "legacy_query";
82
+ const MAX_EAGER_ACTIVITY_RESERVATIONS_PER_WORKFLOW_TASK: usize = 3;
83
+
84
+ type Result<T, E = WFMachinesError> = result::Result<T, E>;
85
+ type BoxedActivationStream = BoxStream<'static, Result<ActivationOrAuto, PollWfError>>;
86
+
87
+ /// Centralizes all state related to workflows and workflow tasks
88
+ pub(crate) struct Workflows {
89
+ task_queue: String,
90
+ local_tx: UnboundedSender<LocalInput>,
91
+ processing_task: tokio::sync::Mutex<Option<JoinHandle<()>>>,
92
+ activation_stream: tokio::sync::Mutex<(
93
+ BoxedActivationStream,
94
+ // Used to indicate polling may begin
95
+ Option<oneshot::Sender<()>>,
96
+ )>,
97
+ client: Arc<dyn WorkerClient>,
98
+ /// Will be populated when this worker is using a cache and should complete WFTs with a sticky
99
+ /// queue.
100
+ sticky_attrs: Option<StickyExecutionAttributes>,
101
+ /// If set, can be used to reserve activity task slots for eager-return of new activity tasks.
102
+ activity_tasks_handle: Option<ActivitiesFromWFTsHandle>,
103
+ }
104
+
105
+ pub(super) struct WorkflowBasics {
106
+ pub max_cached_workflows: usize,
107
+ pub max_outstanding_wfts: usize,
108
+ pub shutdown_token: CancellationToken,
109
+ pub metrics: MetricsContext,
110
+ pub namespace: String,
111
+ pub task_queue: String,
112
+ pub ignore_evicts_on_shutdown: bool,
113
+ }
114
+
115
+ impl Workflows {
116
+ pub(super) fn new(
117
+ basics: WorkflowBasics,
118
+ sticky_attrs: Option<StickyExecutionAttributes>,
119
+ client: Arc<dyn WorkerClient>,
120
+ wft_stream: impl Stream<Item = Result<ValidPollWFTQResponse, tonic::Status>> + Send + 'static,
121
+ local_activity_request_sink: impl Fn(Vec<LocalActRequest>) -> Vec<LocalActivityResolution>
122
+ + Send
123
+ + Sync
124
+ + 'static,
125
+ activity_tasks_handle: Option<ActivitiesFromWFTsHandle>,
126
+ ) -> Self {
127
+ let (local_tx, local_rx) = unbounded_channel();
128
+ let shutdown_tok = basics.shutdown_token.clone();
129
+ let task_queue = basics.task_queue.clone();
130
+ let mut stream = WFStream::build(
131
+ basics,
132
+ wft_stream,
133
+ UnboundedReceiverStream::new(local_rx),
134
+ client.clone(),
135
+ local_activity_request_sink,
136
+ );
137
+ let (activation_tx, activation_rx) = unbounded_channel();
138
+ let (start_polling_tx, start_polling_rx) = oneshot::channel();
139
+ // We must spawn a task to constantly poll the activation stream, because otherwise
140
+ // activation completions would not cause anything to happen until the next poll.
141
+ let processing_task = task::spawn(async move {
142
+ // However, we want to avoid plowing ahead until we've been asked to poll at least once.
143
+ // This supports activity-only workers.
144
+ let do_poll = tokio::select! {
145
+ sp = start_polling_rx => {
146
+ sp.is_ok()
147
+ }
148
+ _ = shutdown_tok.cancelled() => {
149
+ false
150
+ }
151
+ };
152
+ if !do_poll {
153
+ return;
154
+ }
155
+ while let Some(act) = stream.next().await {
156
+ activation_tx
157
+ .send(act)
158
+ .expect("Activation processor channel not dropped");
159
+ }
160
+ });
161
+ Self {
162
+ task_queue,
163
+ local_tx,
164
+ processing_task: tokio::sync::Mutex::new(Some(processing_task)),
165
+ activation_stream: tokio::sync::Mutex::new((
166
+ UnboundedReceiverStream::new(activation_rx).boxed(),
167
+ Some(start_polling_tx),
168
+ )),
169
+ client,
170
+ sticky_attrs,
171
+ activity_tasks_handle,
172
+ }
173
+ }
174
+
175
+ pub async fn next_workflow_activation(&self) -> Result<WorkflowActivation, PollWfError> {
176
+ loop {
177
+ let r = {
178
+ let mut lock = self.activation_stream.lock().await;
179
+ let (ref mut stream, ref mut beginner) = lock.deref_mut();
180
+ if let Some(beginner) = beginner.take() {
181
+ let _ = beginner.send(());
182
+ }
183
+ stream.next().await.unwrap_or(Err(PollWfError::ShutDown))?
184
+ };
185
+ Span::current().record("run_id", r.run_id());
186
+ match r {
187
+ ActivationOrAuto::LangActivation(act) | ActivationOrAuto::ReadyForQueries(act) => {
188
+ debug!(activation=%act, "Sending activation to lang");
189
+ break Ok(act);
190
+ }
191
+ ActivationOrAuto::Autocomplete { run_id } => {
192
+ self.activation_completed(WorkflowActivationCompletion {
193
+ run_id,
194
+ status: Some(workflow_completion::Success::from_variants(vec![]).into()),
195
+ })
196
+ .await?;
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ /// Queue an activation completion for processing, returning a future that will resolve with
203
+ /// the outcome of that completion. See [ActivationCompletedOutcome].
204
+ ///
205
+ /// Returns the most-recently-processed event number for the run
206
+ pub async fn activation_completed(
207
+ &self,
208
+ completion: WorkflowActivationCompletion,
209
+ ) -> Result<usize, CompleteWfError> {
210
+ let is_empty_completion = completion.is_empty();
211
+ let completion = validate_completion(completion)?;
212
+ let run_id = completion.run_id().to_string();
213
+ let (tx, rx) = oneshot::channel();
214
+ let was_sent = self.send_local(WFActCompleteMsg {
215
+ completion,
216
+ response_tx: tx,
217
+ });
218
+ if !was_sent {
219
+ if is_empty_completion {
220
+ // Empty complete which is likely an evict reply, we can just ignore.
221
+ return Ok(0);
222
+ }
223
+ panic!(
224
+ "A non-empty completion was not processed. Workflow processing may have \
225
+ terminated unexpectedly. This is a bug."
226
+ );
227
+ }
228
+
229
+ let completion_outcome = rx
230
+ .await
231
+ .expect("Send half of activation complete response not dropped");
232
+ let mut wft_from_complete = None;
233
+ let reported_wft_to_server = match completion_outcome.outcome {
234
+ ActivationCompleteOutcome::ReportWFTSuccess(report) => match report {
235
+ ServerCommandsWithWorkflowInfo {
236
+ task_token,
237
+ action:
238
+ ActivationAction::WftComplete {
239
+ mut commands,
240
+ query_responses,
241
+ force_new_wft,
242
+ },
243
+ } => {
244
+ let reserved_act_permits =
245
+ self.reserve_activity_slots_for_outgoing_commands(commands.as_mut_slice());
246
+ debug!(commands=%commands.display(), query_responses=%query_responses.display(),
247
+ force_new_wft, "Sending responses to server");
248
+ let mut completion = WorkflowTaskCompletion {
249
+ task_token,
250
+ commands,
251
+ query_responses,
252
+ sticky_attributes: None,
253
+ return_new_workflow_task: true,
254
+ force_create_new_workflow_task: force_new_wft,
255
+ };
256
+ let sticky_attrs = self.sticky_attrs.clone();
257
+ // Do not return new WFT if we would not cache, because returned new WFTs are
258
+ // always partial.
259
+ if sticky_attrs.is_none() {
260
+ completion.return_new_workflow_task = false;
261
+ }
262
+ completion.sticky_attributes = sticky_attrs;
263
+
264
+ self.handle_wft_reporting_errs(&run_id, || async {
265
+ let maybe_wft = self.client.complete_workflow_task(completion).await?;
266
+ if let Some(wft) = maybe_wft.workflow_task {
267
+ wft_from_complete = Some(validate_wft(wft)?);
268
+ }
269
+ self.handle_eager_activities(
270
+ reserved_act_permits,
271
+ maybe_wft.activity_tasks,
272
+ );
273
+ Ok(())
274
+ })
275
+ .await;
276
+ true
277
+ }
278
+ ServerCommandsWithWorkflowInfo {
279
+ task_token,
280
+ action: ActivationAction::RespondLegacyQuery { result },
281
+ } => {
282
+ self.respond_legacy_query(task_token, *result).await;
283
+ true
284
+ }
285
+ },
286
+ ActivationCompleteOutcome::ReportWFTFail(outcome) => match outcome {
287
+ FailedActivationWFTReport::Report(tt, cause, failure) => {
288
+ warn!(run_id=%run_id, failure=?failure, "Failing workflow task");
289
+ self.handle_wft_reporting_errs(&run_id, || async {
290
+ self.client
291
+ .fail_workflow_task(tt, cause, failure.failure.map(Into::into))
292
+ .await
293
+ })
294
+ .await;
295
+ true
296
+ }
297
+ FailedActivationWFTReport::ReportLegacyQueryFailure(task_token, failure) => {
298
+ warn!(run_id=%run_id, failure=?failure, "Failing legacy query request");
299
+ self.respond_legacy_query(task_token, legacy_query_failure(failure))
300
+ .await;
301
+ true
302
+ }
303
+ },
304
+ ActivationCompleteOutcome::DoNothing => false,
305
+ };
306
+
307
+ self.post_activation(PostActivationMsg {
308
+ run_id,
309
+ reported_wft_to_server,
310
+ wft_from_complete,
311
+ });
312
+
313
+ Ok(completion_outcome.most_recently_processed_event)
314
+ }
315
+
316
+ /// Tell workflow that a local activity has finished with the provided result
317
+ pub fn notify_of_local_result(&self, run_id: impl Into<String>, resolved: LocalResolution) {
318
+ self.send_local(LocalResolutionMsg {
319
+ run_id: run_id.into(),
320
+ res: resolved,
321
+ });
322
+ }
323
+
324
+ /// Request eviction of a workflow
325
+ pub fn request_eviction(
326
+ &self,
327
+ run_id: impl Into<String>,
328
+ message: impl Into<String>,
329
+ reason: EvictionReason,
330
+ ) {
331
+ self.send_local(RequestEvictMsg {
332
+ run_id: run_id.into(),
333
+ message: message.into(),
334
+ reason,
335
+ });
336
+ }
337
+
338
+ /// Query the state of workflow management. Can return `None` if workflow state is shut down.
339
+ pub fn get_state_info(&self) -> impl Future<Output = Option<WorkflowStateInfo>> {
340
+ let (tx, rx) = oneshot::channel();
341
+ self.send_local(GetStateInfoMsg { response_tx: tx });
342
+ async move { rx.await.ok() }
343
+ }
344
+
345
+ pub async fn shutdown(&self) -> Result<(), JoinError> {
346
+ let maybe_jh = self.processing_task.lock().await.take();
347
+ if let Some(jh) = maybe_jh {
348
+ // This acts as a final wake up in case the stream is still alive and wouldn't otherwise
349
+ // receive another message. It allows it to shut itself down.
350
+ let _ = self.get_state_info();
351
+ jh.await
352
+ } else {
353
+ Ok(())
354
+ }
355
+ }
356
+
357
+ /// Must be called after every activation completion has finished
358
+ fn post_activation(&self, msg: PostActivationMsg) {
359
+ self.send_local(msg);
360
+ }
361
+
362
+ /// Handle server errors from either completing or failing a workflow task. Un-handleable errors
363
+ /// trigger a workflow eviction and are logged.
364
+ async fn handle_wft_reporting_errs<T, Fut>(&self, run_id: &str, completer: impl FnOnce() -> Fut)
365
+ where
366
+ Fut: Future<Output = Result<T, tonic::Status>>,
367
+ {
368
+ let mut should_evict = None;
369
+ if let Err(err) = completer().await {
370
+ match err.code() {
371
+ // Silence unhandled command errors since the lang SDK cannot do anything
372
+ // about them besides poll again, which it will do anyway.
373
+ tonic::Code::InvalidArgument if err.message() == "UnhandledCommand" => {
374
+ debug!(error = %err, run_id, "Unhandled command response when completing");
375
+ should_evict = Some(EvictionReason::UnhandledCommand);
376
+ }
377
+ tonic::Code::NotFound => {
378
+ warn!(error = %err, run_id, "Task not found when completing");
379
+ should_evict = Some(EvictionReason::TaskNotFound);
380
+ }
381
+ _ => {
382
+ warn!(error= %err, "Network error while completing workflow activation");
383
+ should_evict = Some(EvictionReason::Fatal);
384
+ }
385
+ }
386
+ }
387
+ if let Some(reason) = should_evict {
388
+ self.request_eviction(run_id, "Error reporting WFT to server", reason);
389
+ }
390
+ }
391
+
392
+ /// Sends a message to the workflow processing stream. Returns true if the message was sent
393
+ /// successfully.
394
+ fn send_local(&self, msg: impl Into<LocalInputs>) -> bool {
395
+ let msg = msg.into();
396
+ let print_err = !matches!(msg, LocalInputs::GetStateInfo(_));
397
+ if let Err(e) = self.local_tx.send(LocalInput {
398
+ input: msg,
399
+ span: Span::current(),
400
+ }) {
401
+ if print_err {
402
+ warn!(
403
+ "Tried to interact with workflow state after it shut down. This may be benign \
404
+ when processing evictions during shutdown. When sending {:?}",
405
+ e.0.input
406
+ )
407
+ }
408
+ false
409
+ } else {
410
+ true
411
+ }
412
+ }
413
+
414
+ /// Process eagerly returned activities from WFT completion
415
+ fn handle_eager_activities(
416
+ &self,
417
+ reserved_act_permits: Vec<OwnedMeteredSemPermit>,
418
+ eager_acts: Vec<PollActivityTaskQueueResponse>,
419
+ ) {
420
+ if let Some(at_handle) = self.activity_tasks_handle.as_ref() {
421
+ let excess_reserved = reserved_act_permits.len().saturating_sub(eager_acts.len());
422
+ if excess_reserved > 0 {
423
+ debug!(
424
+ "Server returned {excess_reserved} fewer activities for \
425
+ eager execution than we requested"
426
+ );
427
+ } else if eager_acts.len() > reserved_act_permits.len() {
428
+ // If we somehow got more activities from server than we asked for, server did
429
+ // something wrong.
430
+ error!(
431
+ "Server sent more activities for eager execution than we requested! They will \
432
+ be dropped and eventually time out. Please report this, as it is a server bug."
433
+ )
434
+ }
435
+ let with_permits = reserved_act_permits
436
+ .into_iter()
437
+ .zip(eager_acts.into_iter())
438
+ .map(|(permit, resp)| PermittedTqResp { permit, resp });
439
+ if with_permits.len() > 0 {
440
+ debug!(
441
+ "Adding {} activity tasks received from WFT complete",
442
+ with_permits.len()
443
+ );
444
+ at_handle.add_tasks(with_permits);
445
+ }
446
+ } else if !eager_acts.is_empty() {
447
+ panic!(
448
+ "Requested eager activity execution but this worker has no activity task \
449
+ manager! This is an internal bug, Core should not have asked for tasks."
450
+ )
451
+ }
452
+ }
453
+
454
+ /// Attempt to reserve activity slots for activities we could eagerly execute on
455
+ /// this worker.
456
+ ///
457
+ /// Returns the number of activity slots that were reserved
458
+ fn reserve_activity_slots_for_outgoing_commands(
459
+ &self,
460
+ commands: &mut [Command],
461
+ ) -> Vec<OwnedMeteredSemPermit> {
462
+ let mut reserved = vec![];
463
+ for cmd in commands {
464
+ if let Some(Attributes::ScheduleActivityTaskCommandAttributes(attrs)) =
465
+ cmd.attributes.as_mut()
466
+ {
467
+ // If request_eager_execution was already false, that means lang explicitly
468
+ // told us it didn't want to eagerly execute for some reason. So, we only
469
+ // ever turn *off* eager execution if a slot is not available or the activity
470
+ // is scheduled on a different task queue.
471
+ if attrs.request_eager_execution {
472
+ let same_task_queue = attrs
473
+ .task_queue
474
+ .as_ref()
475
+ .map(|q| q.name == self.task_queue)
476
+ .unwrap_or_default();
477
+ if same_task_queue
478
+ && reserved.len() < MAX_EAGER_ACTIVITY_RESERVATIONS_PER_WORKFLOW_TASK
479
+ {
480
+ if let Some(p) = self
481
+ .activity_tasks_handle
482
+ .as_ref()
483
+ .and_then(|h| h.reserve_slot())
484
+ {
485
+ reserved.push(p);
486
+ } else {
487
+ attrs.request_eager_execution = false;
488
+ }
489
+ } else {
490
+ attrs.request_eager_execution = false;
491
+ }
492
+ }
493
+ }
494
+ }
495
+ reserved
496
+ }
497
+
498
+ /// Wraps responding to legacy queries. Handles ignore-able failures.
499
+ async fn respond_legacy_query(&self, tt: TaskToken, res: QueryResult) {
500
+ match self.client.respond_legacy_query(tt, res).await {
501
+ Ok(_) => {}
502
+ Err(e) if e.code() == tonic::Code::NotFound => {
503
+ warn!(error=?e, "Query not found when attempting to respond to it");
504
+ }
505
+ Err(e) => {
506
+ warn!(error= %e, "Network error while responding to legacy query");
507
+ }
508
+ }
509
+ }
510
+ }
511
+
512
+ /// Manages access to a specific workflow run, and contains various bookkeeping information that the
513
+ /// [WFStream] may need to access quickly.
514
+ #[derive(derive_more::DebugCustom)]
515
+ #[debug(
516
+ fmt = "ManagedRunHandle {{ wft: {:?}, activation: {:?}, buffered_resp: {:?} \
517
+ have_seen_terminal_event: {}, most_recently_processed_event: {}, more_pending_work: {}, \
518
+ trying_to_evict: {}, last_action_acked: {} }}",
519
+ wft,
520
+ activation,
521
+ buffered_resp,
522
+ have_seen_terminal_event,
523
+ most_recently_processed_event_number,
524
+ more_pending_work,
525
+ "trying_to_evict.is_some()",
526
+ last_action_acked
527
+ )]
528
+ struct ManagedRunHandle {
529
+ /// If set, the WFT this run is currently/will be processing.
530
+ wft: Option<OutstandingTask>,
531
+ /// An outstanding activation to lang
532
+ activation: Option<OutstandingActivation>,
533
+ /// If set, it indicates there is a buffered poll response from the server that applies to this
534
+ /// run. This can happen when lang takes too long to complete a task and the task times out, for
535
+ /// example. Upon next completion, the buffered response will be removed and can be made ready
536
+ /// to be returned from polling
537
+ buffered_resp: Option<PermittedWFT>,
538
+ /// True if this machine has seen an event which ends the execution
539
+ have_seen_terminal_event: bool,
540
+ /// The most recently processed event id this machine has seen. 0 means it has seen nothing.
541
+ most_recently_processed_event_number: usize,
542
+ /// Is set true when the machines indicate that there is additional known work to be processed
543
+ more_pending_work: bool,
544
+ /// Is set if an eviction has been requested for this run
545
+ trying_to_evict: Option<RequestEvictMsg>,
546
+ /// Set to true if the last action we tried to take to this run has been processed (ie: the
547
+ /// [RunUpdateResponse] for it has been seen.
548
+ last_action_acked: bool,
549
+ /// For sending work to the machines
550
+ run_actions_tx: UnboundedSender<RunAction>,
551
+ /// Handle to the task where the actual machines live
552
+ handle: JoinHandle<()>,
553
+
554
+ /// We track if we have recorded useful debugging values onto a certain span yet, to overcome
555
+ /// duplicating field values. Remove this once https://github.com/tokio-rs/tracing/issues/2334
556
+ /// is fixed.
557
+ recorded_span_ids: HashSet<tracing::Id>,
558
+ metrics: MetricsContext,
559
+ }
560
+ impl ManagedRunHandle {
561
+ fn new(
562
+ wfm: WorkflowManager,
563
+ activations_tx: UnboundedSender<RunUpdateResponse>,
564
+ local_activity_request_sink: LocalActivityRequestSink,
565
+ metrics: MetricsContext,
566
+ ) -> Self {
567
+ let (run_actions_tx, run_actions_rx) = unbounded_channel();
568
+ let managed = ManagedRun::new(wfm, activations_tx, local_activity_request_sink);
569
+ let handle = tokio::task::spawn(managed.run(run_actions_rx));
570
+ Self {
571
+ wft: None,
572
+ activation: None,
573
+ buffered_resp: None,
574
+ have_seen_terminal_event: false,
575
+ most_recently_processed_event_number: 0,
576
+ more_pending_work: false,
577
+ trying_to_evict: None,
578
+ last_action_acked: true,
579
+ run_actions_tx,
580
+ handle,
581
+ recorded_span_ids: Default::default(),
582
+ metrics,
583
+ }
584
+ }
585
+
586
+ fn incoming_wft(&mut self, wft: NewIncomingWFT) {
587
+ if self.wft.is_some() {
588
+ error!("Trying to send a new WFT for a run which already has one!");
589
+ }
590
+ self.send_run_action(RunActions::NewIncomingWFT(wft));
591
+ }
592
+ fn check_more_activations(&mut self) {
593
+ // No point in checking for more activations if we have not acked the last update, or
594
+ // if there's already an outstanding activation.
595
+ if self.last_action_acked && self.activation.is_none() {
596
+ self.send_run_action(RunActions::CheckMoreWork {
597
+ want_to_evict: self.trying_to_evict.clone(),
598
+ has_pending_queries: self
599
+ .wft
600
+ .as_ref()
601
+ .map(|wft| !wft.pending_queries.is_empty())
602
+ .unwrap_or_default(),
603
+ has_wft: self.wft.is_some(),
604
+ });
605
+ }
606
+ }
607
+ fn send_completion(&mut self, c: RunActivationCompletion) {
608
+ self.send_run_action(RunActions::ActivationCompletion(c));
609
+ }
610
+ fn send_local_resolution(&mut self, r: LocalResolution) {
611
+ self.send_run_action(RunActions::LocalResolution(r));
612
+ }
613
+
614
+ fn insert_outstanding_activation(&mut self, act: &ActivationOrAuto) {
615
+ let act_type = match &act {
616
+ ActivationOrAuto::LangActivation(act) | ActivationOrAuto::ReadyForQueries(act) => {
617
+ if act.is_legacy_query() {
618
+ OutstandingActivation::LegacyQuery
619
+ } else {
620
+ OutstandingActivation::Normal {
621
+ contains_eviction: act.eviction_index().is_some(),
622
+ num_jobs: act.jobs.len(),
623
+ }
624
+ }
625
+ }
626
+ ActivationOrAuto::Autocomplete { .. } => OutstandingActivation::Autocomplete,
627
+ };
628
+ if let Some(old_act) = self.activation {
629
+ // This is a panic because we have screwed up core logic if this is violated. It must be
630
+ // upheld.
631
+ panic!(
632
+ "Attempted to insert a new outstanding activation {:?}, but there already was \
633
+ one outstanding: {:?}",
634
+ act, old_act
635
+ );
636
+ }
637
+ self.activation = Some(act_type);
638
+ }
639
+
640
+ fn send_run_action(&mut self, action: RunActions) {
641
+ self.last_action_acked = false;
642
+ self.run_actions_tx
643
+ .send(RunAction {
644
+ action,
645
+ trace_span: Span::current(),
646
+ })
647
+ .expect("Receive half of run actions not dropped");
648
+ }
649
+
650
+ /// Returns true if the managed run has any form of pending work
651
+ /// If `ignore_evicts` is true, pending evictions do not count as pending work.
652
+ /// If `ignore_buffered` is true, buffered workflow tasks do not count as pending work.
653
+ fn has_any_pending_work(&self, ignore_evicts: bool, ignore_buffered: bool) -> bool {
654
+ let evict_work = if ignore_evicts {
655
+ false
656
+ } else {
657
+ self.trying_to_evict.is_some()
658
+ };
659
+ let act_work = if ignore_evicts {
660
+ if let Some(ref act) = self.activation {
661
+ !act.has_only_eviction()
662
+ } else {
663
+ false
664
+ }
665
+ } else {
666
+ self.activation.is_some()
667
+ };
668
+ let buffered = if ignore_buffered {
669
+ false
670
+ } else {
671
+ self.buffered_resp.is_some()
672
+ };
673
+ self.wft.is_some()
674
+ || buffered
675
+ || !self.last_action_acked
676
+ || self.more_pending_work
677
+ || act_work
678
+ || evict_work
679
+ }
680
+
681
+ /// Returns true if the handle is currently processing a WFT which contains a legacy query.
682
+ fn pending_work_is_legacy_query(&self) -> bool {
683
+ // Either we know because there is a pending legacy query, or it's already been drained and
684
+ // sent as an activation.
685
+ matches!(self.activation, Some(OutstandingActivation::LegacyQuery))
686
+ || self
687
+ .wft
688
+ .as_ref()
689
+ .map(|t| t.has_pending_legacy_query())
690
+ .unwrap_or_default()
691
+ }
692
+ }
693
+
694
+ #[derive(Debug, derive_more::Display)]
695
+ enum ActivationOrAuto {
696
+ LangActivation(WorkflowActivation),
697
+ /// This type should only be filled with an empty activation which is ready to have queries
698
+ /// inserted into the joblist
699
+ ReadyForQueries(WorkflowActivation),
700
+ Autocomplete {
701
+ run_id: String,
702
+ },
703
+ }
704
+ impl ActivationOrAuto {
705
+ pub fn run_id(&self) -> &str {
706
+ match self {
707
+ ActivationOrAuto::LangActivation(act) => &act.run_id,
708
+ ActivationOrAuto::Autocomplete { run_id, .. } => run_id,
709
+ ActivationOrAuto::ReadyForQueries(act) => &act.run_id,
710
+ }
711
+ }
712
+ }
713
+
714
+ #[derive(derive_more::DebugCustom)]
715
+ #[debug(fmt = "PermittedWft {{ {:?} }}", wft)]
716
+ pub(crate) struct PermittedWFT {
717
+ wft: ValidPollWFTQResponse,
718
+ permit: OwnedMeteredSemPermit,
719
+ }
720
+
721
+ #[derive(Debug)]
722
+ pub(crate) struct OutstandingTask {
723
+ pub info: WorkflowTaskInfo,
724
+ pub hit_cache: bool,
725
+ /// Set if the outstanding task has quer(ies) which must be fulfilled upon finishing replay
726
+ pub pending_queries: Vec<QueryWorkflow>,
727
+ pub start_time: Instant,
728
+ /// The WFT permit owned by this task, ensures we don't exceed max concurrent WFT, and makes
729
+ /// sure the permit is automatically freed when we delete the task.
730
+ pub permit: OwnedMeteredSemPermit,
731
+ }
732
+
733
+ impl OutstandingTask {
734
+ pub fn has_pending_legacy_query(&self) -> bool {
735
+ self.pending_queries
736
+ .iter()
737
+ .any(|q| q.query_id == LEGACY_QUERY_ID)
738
+ }
739
+ }
740
+
741
+ #[derive(Copy, Clone, Debug)]
742
+ pub(crate) enum OutstandingActivation {
743
+ /// A normal activation with a joblist
744
+ Normal {
745
+ /// True if there is an eviction in the joblist
746
+ contains_eviction: bool,
747
+ /// Number of jobs in the activation
748
+ num_jobs: usize,
749
+ },
750
+ /// An activation for a legacy query
751
+ LegacyQuery,
752
+ /// A fake activation which is never sent to lang, but used internally
753
+ Autocomplete,
754
+ }
755
+
756
+ impl OutstandingActivation {
757
+ pub(crate) const fn has_only_eviction(self) -> bool {
758
+ matches!(
759
+ self,
760
+ OutstandingActivation::Normal {
761
+ contains_eviction: true,
762
+ num_jobs: nj
763
+ }
764
+ if nj == 1)
765
+ }
766
+ pub(crate) const fn has_eviction(self) -> bool {
767
+ matches!(
768
+ self,
769
+ OutstandingActivation::Normal {
770
+ contains_eviction: true,
771
+ ..
772
+ }
773
+ )
774
+ }
775
+ }
776
+
777
+ /// Contains important information about a given workflow task that we need to memorize while
778
+ /// lang handles it.
779
+ #[derive(Clone, Debug)]
780
+ pub struct WorkflowTaskInfo {
781
+ pub task_token: TaskToken,
782
+ pub attempt: u32,
783
+ /// Exists to allow easy tagging of spans with workflow ids. Is duplicative of info inside the
784
+ /// run machines themselves, but that can't be accessed easily. Would be nice to somehow have a
785
+ /// shared repository, or refcounts, or whatever, for strings like these that get duped all
786
+ /// sorts of places.
787
+ pub wf_id: String,
788
+ }
789
+
790
+ #[derive(Debug)]
791
+ pub enum FailedActivationWFTReport {
792
+ Report(TaskToken, WorkflowTaskFailedCause, Failure),
793
+ ReportLegacyQueryFailure(TaskToken, Failure),
794
+ }
795
+
796
+ #[derive(Debug)]
797
+ pub(crate) struct ServerCommandsWithWorkflowInfo {
798
+ pub task_token: TaskToken,
799
+ pub action: ActivationAction,
800
+ }
801
+
802
+ #[derive(Debug)]
803
+ pub(crate) enum ActivationAction {
804
+ /// We should respond that the workflow task is complete
805
+ WftComplete {
806
+ commands: Vec<ProtoCommand>,
807
+ query_responses: Vec<QueryResult>,
808
+ force_new_wft: bool,
809
+ },
810
+ /// We should respond to a legacy query request
811
+ RespondLegacyQuery { result: Box<QueryResult> },
812
+ }
813
+
814
+ #[derive(Debug, Eq, PartialEq, Hash)]
815
+ pub(crate) enum EvictionRequestResult {
816
+ EvictionRequested(Option<u32>),
817
+ NotFound,
818
+ EvictionAlreadyRequested(Option<u32>),
819
+ }
820
+
821
+ #[derive(Debug)]
822
+ #[allow(dead_code)] // Not always used in non-test
823
+ pub(crate) struct WorkflowStateInfo {
824
+ pub cached_workflows: usize,
825
+ pub outstanding_wft: usize,
826
+ pub available_wft_permits: usize,
827
+ }
828
+
829
+ #[derive(Debug)]
830
+ struct WFActCompleteMsg {
831
+ completion: ValidatedCompletion,
832
+ response_tx: oneshot::Sender<ActivationCompleteResult>,
833
+ }
834
+ #[derive(Debug)]
835
+ struct LocalResolutionMsg {
836
+ run_id: String,
837
+ res: LocalResolution,
838
+ }
839
+ #[derive(Debug)]
840
+ struct PostActivationMsg {
841
+ run_id: String,
842
+ reported_wft_to_server: bool,
843
+ wft_from_complete: Option<ValidPollWFTQResponse>,
844
+ }
845
+ #[derive(Debug, Clone)]
846
+ struct RequestEvictMsg {
847
+ run_id: String,
848
+ message: String,
849
+ reason: EvictionReason,
850
+ }
851
+ #[derive(Debug)]
852
+ struct GetStateInfoMsg {
853
+ response_tx: oneshot::Sender<WorkflowStateInfo>,
854
+ }
855
+
856
+ /// Each activation completion produces one of these
857
+ #[derive(Debug)]
858
+ struct ActivationCompleteResult {
859
+ most_recently_processed_event: usize,
860
+ outcome: ActivationCompleteOutcome,
861
+ }
862
+ /// What needs to be done after calling [Workflows::activation_completed]
863
+ #[derive(Debug)]
864
+ #[allow(clippy::large_enum_variant)]
865
+ enum ActivationCompleteOutcome {
866
+ /// The WFT must be reported as successful to the server using the contained information.
867
+ ReportWFTSuccess(ServerCommandsWithWorkflowInfo),
868
+ /// The WFT must be reported as failed to the server using the contained information.
869
+ ReportWFTFail(FailedActivationWFTReport),
870
+ /// There's nothing to do right now. EX: The workflow needs to keep replaying.
871
+ DoNothing,
872
+ }
873
+ #[derive(Debug)]
874
+ struct FulfillableActivationComplete {
875
+ result: ActivationCompleteResult,
876
+ resp_chan: oneshot::Sender<ActivationCompleteResult>,
877
+ }
878
+ impl FulfillableActivationComplete {
879
+ fn fulfill(self) {
880
+ let _ = self.resp_chan.send(self.result);
881
+ }
882
+ }
883
+
884
+ fn validate_completion(
885
+ completion: WorkflowActivationCompletion,
886
+ ) -> Result<ValidatedCompletion, CompleteWfError> {
887
+ match completion.status {
888
+ Some(workflow_activation_completion::Status::Successful(success)) => {
889
+ // Convert to wf commands
890
+ let commands = success
891
+ .commands
892
+ .into_iter()
893
+ .map(|c| c.try_into())
894
+ .collect::<Result<Vec<_>, EmptyWorkflowCommandErr>>()
895
+ .map_err(|_| CompleteWfError::MalformedWorkflowCompletion {
896
+ reason: "At least one workflow command in the completion contained \
897
+ an empty variant"
898
+ .to_owned(),
899
+ run_id: completion.run_id.clone(),
900
+ })?;
901
+
902
+ if commands.len() > 1
903
+ && commands.iter().any(
904
+ |c| matches!(c, WFCommand::QueryResponse(q) if q.query_id == LEGACY_QUERY_ID),
905
+ )
906
+ {
907
+ return Err(CompleteWfError::MalformedWorkflowCompletion {
908
+ reason: format!(
909
+ "Workflow completion had a legacy query response along with other \
910
+ commands. This is not allowed and constitutes an error in the \
911
+ lang SDK. Commands: {:?}",
912
+ commands
913
+ ),
914
+ run_id: completion.run_id,
915
+ });
916
+ }
917
+
918
+ Ok(ValidatedCompletion::Success {
919
+ run_id: completion.run_id,
920
+ commands,
921
+ })
922
+ }
923
+ Some(workflow_activation_completion::Status::Failed(failure)) => {
924
+ Ok(ValidatedCompletion::Fail {
925
+ run_id: completion.run_id,
926
+ failure,
927
+ })
928
+ }
929
+ None => Err(CompleteWfError::MalformedWorkflowCompletion {
930
+ reason: "Workflow completion had empty status field".to_owned(),
931
+ run_id: completion.run_id,
932
+ }),
933
+ }
934
+ }
935
+
936
+ #[derive(Debug)]
937
+ #[allow(clippy::large_enum_variant)]
938
+ enum ValidatedCompletion {
939
+ Success {
940
+ run_id: String,
941
+ commands: Vec<WFCommand>,
942
+ },
943
+ Fail {
944
+ run_id: String,
945
+ failure: Failure,
946
+ },
947
+ }
948
+
949
+ impl ValidatedCompletion {
950
+ pub fn run_id(&self) -> &str {
951
+ match self {
952
+ ValidatedCompletion::Success { run_id, .. } => run_id,
953
+ ValidatedCompletion::Fail { run_id, .. } => run_id,
954
+ }
955
+ }
956
+ }
957
+
958
+ /// Input to run tasks, sent to [ManagedRun]s via [ManagedRunHandle]s
959
+ #[derive(Debug)]
960
+ struct RunAction {
961
+ action: RunActions,
962
+ trace_span: Span,
963
+ }
964
+ #[derive(Debug)]
965
+ #[allow(clippy::large_enum_variant)]
966
+ enum RunActions {
967
+ NewIncomingWFT(NewIncomingWFT),
968
+ ActivationCompletion(RunActivationCompletion),
969
+ CheckMoreWork {
970
+ want_to_evict: Option<RequestEvictMsg>,
971
+ has_pending_queries: bool,
972
+ has_wft: bool,
973
+ },
974
+ LocalResolution(LocalResolution),
975
+ HeartbeatTimeout,
976
+ }
977
+ #[derive(Debug)]
978
+ struct NewIncomingWFT {
979
+ /// This field is only populated if the machines already exist. Otherwise the machines
980
+ /// are instantiated with the workflow history.
981
+ history_update: Option<HistoryUpdate>,
982
+ /// Wft start time
983
+ start_time: Instant,
984
+ }
985
+ #[derive(Debug)]
986
+ struct RunActivationCompletion {
987
+ task_token: TaskToken,
988
+ start_time: Instant,
989
+ commands: Vec<WFCommand>,
990
+ activation_was_eviction: bool,
991
+ activation_was_only_eviction: bool,
992
+ has_pending_query: bool,
993
+ query_responses: Vec<QueryResult>,
994
+ /// Used to notify the worker when the completion is done processing and the completion can
995
+ /// unblock. Must always be `Some` when initialized.
996
+ resp_chan: Option<oneshot::Sender<ActivationCompleteResult>>,
997
+ }
998
+
999
+ /// A response from a [ManagedRun] held by a [ManagedRunHandle]
1000
+ #[derive(Debug)]
1001
+ struct RunUpdateResponse {
1002
+ kind: RunUpdateResponseKind,
1003
+ span: Span,
1004
+ }
1005
+ #[derive(Debug, derive_more::Display)]
1006
+ #[allow(clippy::large_enum_variant)]
1007
+ enum RunUpdateResponseKind {
1008
+ Good(GoodRunUpdate),
1009
+ Fail(FailRunUpdate),
1010
+ }
1011
+ impl RunUpdateResponseKind {
1012
+ pub(crate) fn run_id(&self) -> &str {
1013
+ match self {
1014
+ RunUpdateResponseKind::Good(g) => &g.run_id,
1015
+ RunUpdateResponseKind::Fail(f) => &f.run_id,
1016
+ }
1017
+ }
1018
+ }
1019
+
1020
+ #[derive(Debug)]
1021
+ struct GoodRunUpdate {
1022
+ run_id: String,
1023
+ outgoing_activation: Option<ActivationOrAuto>,
1024
+ fulfillable_complete: Option<FulfillableActivationComplete>,
1025
+ have_seen_terminal_event: bool,
1026
+ /// Is true if there are more jobs that need to be sent to lang
1027
+ more_pending_work: bool,
1028
+ most_recently_processed_event_number: usize,
1029
+ /// Is true if this update was in response to a new WFT
1030
+ in_response_to_wft: bool,
1031
+ }
1032
+ impl Display for GoodRunUpdate {
1033
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1034
+ write!(
1035
+ f,
1036
+ "GoodRunUpdate(run_id: {}, outgoing_activation: {}, more_pending_work: {})",
1037
+ self.run_id,
1038
+ if let Some(og) = self.outgoing_activation.as_ref() {
1039
+ format!("{}", og)
1040
+ } else {
1041
+ "None".to_string()
1042
+ },
1043
+ self.more_pending_work
1044
+ )
1045
+ }
1046
+ }
1047
+ #[derive(Debug)]
1048
+ pub(crate) struct FailRunUpdate {
1049
+ run_id: String,
1050
+ err: WFMachinesError,
1051
+ /// This is populated if the run update failed while processing a completion - and thus we
1052
+ /// must respond down it when handling the failure.
1053
+ completion_resp: Option<oneshot::Sender<ActivationCompleteResult>>,
1054
+ }
1055
+ impl Display for FailRunUpdate {
1056
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1057
+ write!(
1058
+ f,
1059
+ "FailRunUpdate(run_id: {}, error: {:?})",
1060
+ self.run_id, self.err
1061
+ )
1062
+ }
1063
+ }
1064
+ #[derive(Debug)]
1065
+ pub struct OutgoingServerCommands {
1066
+ pub commands: Vec<ProtoCommand>,
1067
+ pub replaying: bool,
1068
+ }
1069
+
1070
+ #[derive(Debug)]
1071
+ pub(crate) enum LocalResolution {
1072
+ LocalActivity(LocalActivityResolution),
1073
+ }
1074
+
1075
+ #[derive(thiserror::Error, Debug, derive_more::From)]
1076
+ #[error("Lang provided workflow command with empty variant")]
1077
+ pub struct EmptyWorkflowCommandErr;
1078
+
1079
+ /// [DrivenWorkflow]s respond with these when called, to indicate what they want to do next.
1080
+ /// EX: Create a new timer, complete the workflow, etc.
1081
+ #[derive(Debug, derive_more::From, derive_more::Display)]
1082
+ #[allow(clippy::large_enum_variant)]
1083
+ pub enum WFCommand {
1084
+ /// Returned when we need to wait for the lang sdk to send us something
1085
+ NoCommandsFromLang,
1086
+ AddActivity(ScheduleActivity),
1087
+ AddLocalActivity(ScheduleLocalActivity),
1088
+ RequestCancelActivity(RequestCancelActivity),
1089
+ RequestCancelLocalActivity(RequestCancelLocalActivity),
1090
+ AddTimer(StartTimer),
1091
+ CancelTimer(CancelTimer),
1092
+ CompleteWorkflow(CompleteWorkflowExecution),
1093
+ FailWorkflow(FailWorkflowExecution),
1094
+ QueryResponse(QueryResult),
1095
+ ContinueAsNew(ContinueAsNewWorkflowExecution),
1096
+ CancelWorkflow(CancelWorkflowExecution),
1097
+ SetPatchMarker(SetPatchMarker),
1098
+ AddChildWorkflow(StartChildWorkflowExecution),
1099
+ CancelChild(CancelChildWorkflowExecution),
1100
+ RequestCancelExternalWorkflow(RequestCancelExternalWorkflowExecution),
1101
+ SignalExternalWorkflow(SignalExternalWorkflowExecution),
1102
+ CancelSignalWorkflow(CancelSignalWorkflow),
1103
+ UpsertSearchAttributes(UpsertWorkflowSearchAttributes),
1104
+ ModifyWorkflowProperties(ModifyWorkflowProperties),
1105
+ }
1106
+
1107
+ impl TryFrom<WorkflowCommand> for WFCommand {
1108
+ type Error = EmptyWorkflowCommandErr;
1109
+
1110
+ fn try_from(c: WorkflowCommand) -> result::Result<Self, Self::Error> {
1111
+ match c.variant.ok_or(EmptyWorkflowCommandErr)? {
1112
+ workflow_command::Variant::StartTimer(s) => Ok(Self::AddTimer(s)),
1113
+ workflow_command::Variant::CancelTimer(s) => Ok(Self::CancelTimer(s)),
1114
+ workflow_command::Variant::ScheduleActivity(s) => Ok(Self::AddActivity(s)),
1115
+ workflow_command::Variant::RequestCancelActivity(s) => {
1116
+ Ok(Self::RequestCancelActivity(s))
1117
+ }
1118
+ workflow_command::Variant::CompleteWorkflowExecution(c) => {
1119
+ Ok(Self::CompleteWorkflow(c))
1120
+ }
1121
+ workflow_command::Variant::FailWorkflowExecution(s) => Ok(Self::FailWorkflow(s)),
1122
+ workflow_command::Variant::RespondToQuery(s) => Ok(Self::QueryResponse(s)),
1123
+ workflow_command::Variant::ContinueAsNewWorkflowExecution(s) => {
1124
+ Ok(Self::ContinueAsNew(s))
1125
+ }
1126
+ workflow_command::Variant::CancelWorkflowExecution(s) => Ok(Self::CancelWorkflow(s)),
1127
+ workflow_command::Variant::SetPatchMarker(s) => Ok(Self::SetPatchMarker(s)),
1128
+ workflow_command::Variant::StartChildWorkflowExecution(s) => {
1129
+ Ok(Self::AddChildWorkflow(s))
1130
+ }
1131
+ workflow_command::Variant::RequestCancelExternalWorkflowExecution(s) => {
1132
+ Ok(Self::RequestCancelExternalWorkflow(s))
1133
+ }
1134
+ workflow_command::Variant::SignalExternalWorkflowExecution(s) => {
1135
+ Ok(Self::SignalExternalWorkflow(s))
1136
+ }
1137
+ workflow_command::Variant::CancelSignalWorkflow(s) => Ok(Self::CancelSignalWorkflow(s)),
1138
+ workflow_command::Variant::CancelChildWorkflowExecution(s) => Ok(Self::CancelChild(s)),
1139
+ workflow_command::Variant::ScheduleLocalActivity(s) => Ok(Self::AddLocalActivity(s)),
1140
+ workflow_command::Variant::RequestCancelLocalActivity(s) => {
1141
+ Ok(Self::RequestCancelLocalActivity(s))
1142
+ }
1143
+ workflow_command::Variant::UpsertWorkflowSearchAttributes(s) => {
1144
+ Ok(Self::UpsertSearchAttributes(s))
1145
+ }
1146
+ workflow_command::Variant::ModifyWorkflowProperties(s) => {
1147
+ Ok(Self::ModifyWorkflowProperties(s))
1148
+ }
1149
+ }
1150
+ }
1151
+ }
1152
+
1153
+ #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
1154
+ enum CommandID {
1155
+ Timer(u32),
1156
+ Activity(u32),
1157
+ LocalActivity(u32),
1158
+ ChildWorkflowStart(u32),
1159
+ SignalExternal(u32),
1160
+ CancelExternal(u32),
1161
+ }
1162
+
1163
+ /// Details remembered from the workflow execution started event that we may need to recall later.
1164
+ /// Is a subset of `WorkflowExecutionStartedEventAttributes`, but avoids holding on to huge fields.
1165
+ #[derive(Debug, Clone)]
1166
+ pub struct WorkflowStartedInfo {
1167
+ workflow_task_timeout: Option<Duration>,
1168
+ workflow_execution_timeout: Option<Duration>,
1169
+ memo: Option<Memo>,
1170
+ search_attrs: Option<SearchAttributes>,
1171
+ retry_policy: Option<RetryPolicy>,
1172
+ }
1173
+
1174
+ type LocalActivityRequestSink =
1175
+ Arc<dyn Fn(Vec<LocalActRequest>) -> Vec<LocalActivityResolution> + Send + Sync>;
1176
+
1177
+ /// Wraps outgoing activation job protos with some internal details core might care about
1178
+ #[derive(Debug, derive_more::Display)]
1179
+ #[display(fmt = "{}", variant)]
1180
+ struct OutgoingJob {
1181
+ variant: workflow_activation_job::Variant,
1182
+ /// Since LA resolutions are not distinguished from non-LA resolutions as far as lang is
1183
+ /// concerned, but core cares about that sometimes, attach that info here.
1184
+ is_la_resolution: bool,
1185
+ }
1186
+ impl<WA: Into<workflow_activation_job::Variant>> From<WA> for OutgoingJob {
1187
+ fn from(wa: WA) -> Self {
1188
+ Self {
1189
+ variant: wa.into(),
1190
+ is_la_resolution: false,
1191
+ }
1192
+ }
1193
+ }
1194
+ impl From<OutgoingJob> for WorkflowActivationJob {
1195
+ fn from(og: OutgoingJob) -> Self {
1196
+ Self {
1197
+ variant: Some(og.variant),
1198
+ }
1199
+ }
1200
+ }