temporalio 0.0.0 → 0.0.1

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