temporalio 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +301 -0
  3. data/bridge/Cargo.lock +2888 -0
  4. data/bridge/Cargo.toml +27 -0
  5. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  6. data/bridge/sdk-core/Cargo.lock +2606 -0
  7. data/bridge/sdk-core/Cargo.toml +2 -0
  8. data/bridge/sdk-core/LICENSE.txt +23 -0
  9. data/bridge/sdk-core/README.md +104 -0
  10. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  11. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  13. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  14. data/bridge/sdk-core/client/Cargo.toml +40 -0
  15. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  16. data/bridge/sdk-core/client/src/lib.rs +1286 -0
  17. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  18. data/bridge/sdk-core/client/src/raw.rs +932 -0
  19. data/bridge/sdk-core/client/src/retry.rs +751 -0
  20. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  21. data/bridge/sdk-core/core/Cargo.toml +116 -0
  22. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  23. data/bridge/sdk-core/core/benches/workflow_replay.rs +76 -0
  24. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  25. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -0
  26. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  27. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  28. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +925 -0
  29. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  30. data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -0
  31. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  32. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  33. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  34. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2090 -0
  35. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  36. data/bridge/sdk-core/core/src/lib.rs +282 -0
  37. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  38. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  39. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  40. data/bridge/sdk-core/core/src/replay/mod.rs +215 -0
  41. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  42. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  43. data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
  44. data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
  45. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
  46. data/bridge/sdk-core/core/src/test_help/mod.rs +889 -0
  47. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  48. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1048 -0
  49. data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
  50. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  51. data/bridge/sdk-core/core/src/worker/client.rs +373 -0
  52. data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
  53. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  54. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
  55. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
  60. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1200 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +655 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +985 -0
  80. data/bridge/sdk-core/core-api/Cargo.toml +32 -0
  81. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  82. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  83. data/bridge/sdk-core/core-api/src/lib.rs +109 -0
  84. data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
  85. data/bridge/sdk-core/core-api/src/worker.rs +148 -0
  86. data/bridge/sdk-core/etc/deps.svg +162 -0
  87. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  88. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  89. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  90. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  91. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  92. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  93. data/bridge/sdk-core/fsm/README.md +3 -0
  94. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  95. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  96. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  97. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  98. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  99. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  100. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  115. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  116. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  117. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  118. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  119. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  120. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  121. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  122. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  123. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  124. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  125. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  126. data/bridge/sdk-core/protos/api_upstream/buf.yaml +9 -0
  127. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  128. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  129. data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
  130. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  131. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  132. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +47 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +56 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +40 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +758 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +121 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +379 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -0
  164. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  165. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  166. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +263 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  174. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  175. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  176. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  179. data/bridge/sdk-core/rustfmt.toml +1 -0
  180. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  181. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  182. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  183. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  184. data/bridge/sdk-core/sdk/src/interceptors.rs +50 -0
  185. data/bridge/sdk-core/sdk/src/lib.rs +794 -0
  186. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  187. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  188. data/bridge/sdk-core/sdk/src/workflow_context.rs +694 -0
  189. data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -0
  190. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  191. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  192. data/bridge/sdk-core/sdk-core-protos/build.rs +107 -0
  193. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  194. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
  195. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  196. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  199. data/bridge/sdk-core/test-utils/Cargo.toml +36 -0
  200. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  201. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  202. data/bridge/sdk-core/test-utils/src/lib.rs +650 -0
  203. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  204. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  205. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +221 -0
  206. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  207. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -0
  208. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  209. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  210. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  211. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  212. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +788 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +223 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +597 -0
  227. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  228. data/bridge/sdk-core/tests/main.rs +113 -0
  229. data/bridge/sdk-core/tests/runner.rs +93 -0
  230. data/bridge/src/connection.rs +186 -0
  231. data/bridge/src/lib.rs +239 -0
  232. data/bridge/src/runtime.rs +54 -0
  233. data/bridge/src/worker.rs +124 -0
  234. data/ext/Rakefile +9 -0
  235. data/lib/bridge.so +0 -0
  236. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  237. data/lib/gen/temporal/api/batch/v1/message_pb.rb +50 -0
  238. data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
  239. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  240. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
  241. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
  242. data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
  243. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
  244. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
  245. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -0
  246. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  247. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  248. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  249. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  250. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  251. data/lib/gen/temporal/api/enums/v1/update_pb.rb +23 -0
  252. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  253. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  254. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  255. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  256. data/lib/gen/temporal/api/history/v1/message_pb.rb +490 -0
  257. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
  258. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  259. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -0
  260. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  261. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  262. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  263. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +149 -0
  264. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  265. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  266. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
  267. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -0
  268. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  269. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  270. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  271. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  272. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  273. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  274. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  275. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  276. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +165 -0
  277. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
  278. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  279. data/lib/temporalio/activity/context.rb +97 -0
  280. data/lib/temporalio/activity/info.rb +67 -0
  281. data/lib/temporalio/activity.rb +85 -0
  282. data/lib/temporalio/bridge/error.rb +8 -0
  283. data/lib/temporalio/bridge.rb +14 -0
  284. data/lib/temporalio/client/implementation.rb +340 -0
  285. data/lib/temporalio/client/workflow_handle.rb +243 -0
  286. data/lib/temporalio/client.rb +131 -0
  287. data/lib/temporalio/connection.rb +751 -0
  288. data/lib/temporalio/data_converter.rb +191 -0
  289. data/lib/temporalio/error/failure.rb +194 -0
  290. data/lib/temporalio/error/workflow_failure.rb +19 -0
  291. data/lib/temporalio/errors.rb +40 -0
  292. data/lib/temporalio/failure_converter/base.rb +26 -0
  293. data/lib/temporalio/failure_converter/basic.rb +319 -0
  294. data/lib/temporalio/failure_converter.rb +7 -0
  295. data/lib/temporalio/interceptor/chain.rb +28 -0
  296. data/lib/temporalio/interceptor/client.rb +123 -0
  297. data/lib/temporalio/payload_codec/base.rb +32 -0
  298. data/lib/temporalio/payload_converter/base.rb +24 -0
  299. data/lib/temporalio/payload_converter/bytes.rb +27 -0
  300. data/lib/temporalio/payload_converter/composite.rb +49 -0
  301. data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
  302. data/lib/temporalio/payload_converter/json.rb +26 -0
  303. data/lib/temporalio/payload_converter/nil.rb +26 -0
  304. data/lib/temporalio/payload_converter.rb +14 -0
  305. data/lib/temporalio/retry_policy.rb +82 -0
  306. data/lib/temporalio/retry_state.rb +35 -0
  307. data/lib/temporalio/runtime.rb +25 -0
  308. data/lib/temporalio/timeout_type.rb +29 -0
  309. data/lib/temporalio/version.rb +3 -0
  310. data/lib/temporalio/worker/activity_runner.rb +92 -0
  311. data/lib/temporalio/worker/activity_worker.rb +138 -0
  312. data/lib/temporalio/worker/reactor.rb +46 -0
  313. data/lib/temporalio/worker/runner.rb +63 -0
  314. data/lib/temporalio/worker/sync_worker.rb +88 -0
  315. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  316. data/lib/temporalio/worker.rb +198 -0
  317. data/lib/temporalio/workflow/execution_info.rb +54 -0
  318. data/lib/temporalio/workflow/execution_status.rb +36 -0
  319. data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
  320. data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
  321. data/lib/temporalio.rb +12 -1
  322. data/lib/thermite_patch.rb +23 -0
  323. data/temporalio.gemspec +45 -0
  324. metadata +566 -9
  325. data/lib/temporal/version.rb +0 -3
  326. data/lib/temporal.rb +0 -4
  327. data/temporal.gemspec +0 -20
@@ -0,0 +1,794 @@
1
+ #![warn(missing_docs)] // error if there are missing docs
2
+
3
+ //! This crate defines an alpha-stage Temporal Rust SDK.
4
+ //!
5
+ //! Currently defining activities and running an activity-only worker is the most stable code.
6
+ //! Workflow definitions exist and running a workflow worker works, but the API is still very
7
+ //! unstable.
8
+ //!
9
+ //! An example of running an activity worker:
10
+ //! ```no_run
11
+ //! use std::{str::FromStr, sync::Arc};
12
+ //! use temporal_sdk::{sdk_client_options, ActContext, Worker};
13
+ //! use temporal_sdk_core::{init_worker, Url, CoreRuntime};
14
+ //! use temporal_sdk_core_api::{worker::WorkerConfigBuilder, telemetry::TelemetryOptionsBuilder};
15
+ //!
16
+ //! #[tokio::main]
17
+ //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
18
+ //! let server_options = sdk_client_options(Url::from_str("http://localhost:7233")?).build()?;
19
+ //!
20
+ //! let client = server_options.connect("default", None, None).await?;
21
+ //!
22
+ //! let telemetry_options = TelemetryOptionsBuilder::default().build()?;
23
+ //! let runtime = CoreRuntime::new_assume_tokio(telemetry_options)?;
24
+ //!
25
+ //! let worker_config = WorkerConfigBuilder::default()
26
+ //! .namespace("default")
27
+ //! .task_queue("task_queue")
28
+ //! .build()?;
29
+ //!
30
+ //! let core_worker = init_worker(&runtime, worker_config, client)?;
31
+ //!
32
+ //! let mut worker = Worker::new_from_core(Arc::new(core_worker), "task_queue");
33
+ //! worker.register_activity(
34
+ //! "echo_activity",
35
+ //! |_ctx: ActContext, echo_me: String| async move { Ok(echo_me) },
36
+ //! );
37
+ //!
38
+ //! worker.run().await?;
39
+ //!
40
+ //! Ok(())
41
+ //! }
42
+ //! ```
43
+
44
+ #[macro_use]
45
+ extern crate tracing;
46
+
47
+ mod activity_context;
48
+ mod app_data;
49
+ pub mod interceptors;
50
+ mod payload_converter;
51
+ mod workflow_context;
52
+ mod workflow_future;
53
+
54
+ pub use activity_context::ActContext;
55
+ pub use temporal_client::Namespace;
56
+ pub use workflow_context::{
57
+ ActivityOptions, CancellableFuture, ChildWorkflow, ChildWorkflowOptions, LocalActivityOptions,
58
+ Signal, SignalData, SignalWorkflowOptions, WfContext,
59
+ };
60
+
61
+ use crate::{
62
+ interceptors::WorkerInterceptor,
63
+ workflow_context::{ChildWfCommon, PendingChildWorkflow},
64
+ };
65
+ use anyhow::{anyhow, bail, Context};
66
+ use app_data::AppData;
67
+ use futures::{future::BoxFuture, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
68
+ use std::{
69
+ cell::RefCell,
70
+ collections::HashMap,
71
+ fmt::{Debug, Display, Formatter},
72
+ future::Future,
73
+ sync::Arc,
74
+ };
75
+ use temporal_client::ClientOptionsBuilder;
76
+ use temporal_sdk_core::Url;
77
+ use temporal_sdk_core_api::{
78
+ errors::{PollActivityError, PollWfError},
79
+ Worker as CoreWorker,
80
+ };
81
+ use temporal_sdk_core_protos::{
82
+ coresdk::{
83
+ activity_result::{ActivityExecutionResult, ActivityResolution},
84
+ activity_task::{activity_task, ActivityTask},
85
+ child_workflow::ChildWorkflowResult,
86
+ common::NamespacedWorkflowExecution,
87
+ workflow_activation::{
88
+ resolve_child_workflow_execution_start::Status as ChildWorkflowStartStatus,
89
+ workflow_activation_job::Variant, WorkflowActivation, WorkflowActivationJob,
90
+ },
91
+ workflow_commands::{workflow_command, ContinueAsNewWorkflowExecution},
92
+ workflow_completion::WorkflowActivationCompletion,
93
+ ActivityTaskCompletion, AsJsonPayloadExt, FromJsonPayloadExt,
94
+ },
95
+ temporal::api::{common::v1::Payload, failure::v1::Failure},
96
+ TaskToken,
97
+ };
98
+ use tokio::{
99
+ sync::{
100
+ mpsc::{unbounded_channel, UnboundedSender},
101
+ oneshot,
102
+ },
103
+ task::JoinError,
104
+ };
105
+ use tokio_stream::wrappers::UnboundedReceiverStream;
106
+ use tokio_util::sync::CancellationToken;
107
+
108
+ const VERSION: &str = env!("CARGO_PKG_VERSION");
109
+
110
+ /// Returns a [ClientOptionsBuilder] with required fields set to appropriate values
111
+ /// for the Rust SDK.
112
+ pub fn sdk_client_options(url: impl Into<Url>) -> ClientOptionsBuilder {
113
+ let mut builder = ClientOptionsBuilder::default();
114
+ builder
115
+ .target_url(url)
116
+ .client_name("rust-sdk".to_string())
117
+ .client_version(VERSION.to_string());
118
+
119
+ builder
120
+ }
121
+
122
+ /// A worker that can poll for and respond to workflow tasks by using [WorkflowFunction]s,
123
+ /// and activity tasks by using [ActivityFunction]s
124
+ pub struct Worker {
125
+ common: CommonWorker,
126
+ workflow_half: WorkflowHalf,
127
+ activity_half: ActivityHalf,
128
+ app_data: Option<AppData>,
129
+ }
130
+
131
+ struct CommonWorker {
132
+ worker: Arc<dyn CoreWorker>,
133
+ task_queue: String,
134
+ worker_interceptor: Option<Box<dyn WorkerInterceptor>>,
135
+ }
136
+
137
+ struct WorkflowHalf {
138
+ /// Maps run id to cached workflow state
139
+ workflows: RefCell<HashMap<String, WorkflowData>>,
140
+ /// Maps workflow type to the function for executing workflow runs with that ID
141
+ workflow_fns: RefCell<HashMap<String, WorkflowFunction>>,
142
+ }
143
+ struct WorkflowData {
144
+ /// Channel used to send the workflow activations
145
+ activation_chan: UnboundedSender<WorkflowActivation>,
146
+ }
147
+
148
+ struct WorkflowFutureHandle<F: Future<Output = Result<WorkflowResult<()>, JoinError>>> {
149
+ join_handle: F,
150
+ run_id: String,
151
+ }
152
+
153
+ struct ActivityHalf {
154
+ /// Maps activity type to the function for executing activities of that type
155
+ activity_fns: HashMap<String, ActivityFunction>,
156
+ task_tokens_to_cancels: HashMap<TaskToken, CancellationToken>,
157
+ }
158
+
159
+ impl Worker {
160
+ /// Create a new Rust SDK worker from a core worker
161
+ pub fn new_from_core(worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
162
+ Self {
163
+ common: CommonWorker {
164
+ worker,
165
+ task_queue: task_queue.into(),
166
+ worker_interceptor: None,
167
+ },
168
+ workflow_half: WorkflowHalf {
169
+ workflows: Default::default(),
170
+ workflow_fns: Default::default(),
171
+ },
172
+ activity_half: ActivityHalf {
173
+ activity_fns: Default::default(),
174
+ task_tokens_to_cancels: Default::default(),
175
+ },
176
+ app_data: Some(Default::default()),
177
+ }
178
+ }
179
+
180
+ /// Returns the task queue name this worker polls on
181
+ pub fn task_queue(&self) -> &str {
182
+ &self.common.task_queue
183
+ }
184
+
185
+ /// Return a handle that can be used to initiate shutdown.
186
+ /// TODO: Doc better after shutdown changes
187
+ pub fn shutdown_handle(&self) -> impl Fn() {
188
+ let w = self.common.worker.clone();
189
+ move || w.initiate_shutdown()
190
+ }
191
+
192
+ /// Register a Workflow function to invoke when the Worker is asked to run a workflow of
193
+ /// `workflow_type`
194
+ pub fn register_wf<F: Into<WorkflowFunction>>(
195
+ &mut self,
196
+ workflow_type: impl Into<String>,
197
+ wf_function: F,
198
+ ) {
199
+ self.workflow_half
200
+ .workflow_fns
201
+ .get_mut()
202
+ .insert(workflow_type.into(), wf_function.into());
203
+ }
204
+
205
+ /// Register an Activity function to invoke when the Worker is asked to run an activity of
206
+ /// `activity_type`
207
+ pub fn register_activity<A, R, O>(
208
+ &mut self,
209
+ activity_type: impl Into<String>,
210
+ act_function: impl IntoActivityFunc<A, R, O>,
211
+ ) {
212
+ self.activity_half.activity_fns.insert(
213
+ activity_type.into(),
214
+ ActivityFunction {
215
+ act_func: act_function.into_activity_fn(),
216
+ },
217
+ );
218
+ }
219
+
220
+ /// Insert Custom App Context for Workflows and Activities
221
+ pub fn insert_app_data<T: Send + Sync + 'static>(&mut self, data: T) {
222
+ self.app_data.as_mut().map(|a| a.insert(data));
223
+ }
224
+
225
+ /// Runs the worker. Eventually resolves after the worker has been explicitly shut down,
226
+ /// or may return early with an error in the event of some unresolvable problem.
227
+ pub async fn run(&mut self) -> Result<(), anyhow::Error> {
228
+ let shutdown_token = CancellationToken::new();
229
+ let (common, wf_half, act_half, app_data) = self.split_apart();
230
+ let safe_app_data = Arc::new(
231
+ app_data
232
+ .take()
233
+ .ok_or_else(|| anyhow!("app_data should exist on run"))?,
234
+ );
235
+ let (wf_future_tx, wf_future_rx) = unbounded_channel();
236
+ let (completions_tx, completions_rx) = unbounded_channel();
237
+ let wf_future_joiner = async {
238
+ UnboundedReceiverStream::new(wf_future_rx)
239
+ .map(Result::<_, anyhow::Error>::Ok)
240
+ .try_for_each_concurrent(
241
+ None,
242
+ |WorkflowFutureHandle {
243
+ join_handle,
244
+ run_id,
245
+ }| {
246
+ let wf_half = &*wf_half;
247
+ async move {
248
+ join_handle.await??;
249
+ info!(run_id=%run_id, "Removing workflow from cache");
250
+ wf_half.workflows.borrow_mut().remove(&run_id);
251
+ Ok(())
252
+ }
253
+ },
254
+ )
255
+ .await
256
+ .context("Workflow futures encountered an error")
257
+ };
258
+ let wf_completion_processor = async {
259
+ UnboundedReceiverStream::new(completions_rx)
260
+ .map(Ok)
261
+ .try_for_each_concurrent(None, |completion| async {
262
+ if let Some(ref i) = common.worker_interceptor {
263
+ i.on_workflow_activation_completion(&completion).await;
264
+ }
265
+ common.worker.complete_workflow_activation(completion).await
266
+ })
267
+ .map_err(anyhow::Error::from)
268
+ .await
269
+ .context("Workflow completions processor encountered an error")
270
+ };
271
+ tokio::try_join!(
272
+ // Workflow polling loop
273
+ async {
274
+ loop {
275
+ let activation = match common.worker.poll_workflow_activation().await {
276
+ Err(PollWfError::ShutDown) => {
277
+ break;
278
+ }
279
+ o => o?,
280
+ };
281
+ if let Some(ref i) = common.worker_interceptor {
282
+ i.on_workflow_activation(&activation).await?;
283
+ }
284
+ if let Some(wf_fut) = wf_half.workflow_activation_handler(
285
+ common,
286
+ shutdown_token.clone(),
287
+ activation,
288
+ &completions_tx,
289
+ )? {
290
+ if wf_future_tx.send(wf_fut).is_err() {
291
+ panic!(
292
+ "Receive half of completion processor channel cannot be dropped"
293
+ );
294
+ }
295
+ }
296
+ }
297
+ // Tell still-alive workflows to evict themselves
298
+ shutdown_token.cancel();
299
+ // It's important to drop these so the future and completion processors will
300
+ // terminate.
301
+ drop(wf_future_tx);
302
+ drop(completions_tx);
303
+ Result::<_, anyhow::Error>::Ok(())
304
+ },
305
+ // Only poll on the activity queue if activity functions have been registered. This
306
+ // makes tests which use mocks dramatically more manageable.
307
+ async {
308
+ if !act_half.activity_fns.is_empty() {
309
+ let shutdown_token = shutdown_token.clone();
310
+ loop {
311
+ tokio::select! {
312
+ activity = common.worker.poll_activity_task() => {
313
+ if matches!(activity, Err(PollActivityError::ShutDown)) {
314
+ break;
315
+ }
316
+ act_half.activity_task_handler(
317
+ common.worker.clone(),
318
+ safe_app_data.clone(),
319
+ common.task_queue.clone(),
320
+ activity?
321
+ )?;
322
+ },
323
+ _ = shutdown_token.cancelled() => { break }
324
+ }
325
+ }
326
+ };
327
+ Result::<_, anyhow::Error>::Ok(())
328
+ },
329
+ wf_future_joiner,
330
+ wf_completion_processor,
331
+ )?;
332
+
333
+ info!("Polling loops exited");
334
+ if let Some(i) = self.common.worker_interceptor.as_ref() {
335
+ i.on_shutdown(self);
336
+ }
337
+ self.common.worker.shutdown().await;
338
+ self.app_data = Some(
339
+ Arc::try_unwrap(safe_app_data)
340
+ .map_err(|_| anyhow!("some references of AppData exist on worker shutdown"))?,
341
+ );
342
+ Ok(())
343
+ }
344
+
345
+ /// Set a [WorkerInterceptor]
346
+ pub fn set_worker_interceptor(&mut self, interceptor: Box<dyn WorkerInterceptor>) {
347
+ self.common.worker_interceptor = Some(interceptor);
348
+ }
349
+
350
+ /// Turns this rust worker into a new worker with all the same workflows and activities
351
+ /// registered, but with a new underlying core worker. Can be used to swap the worker for
352
+ /// a replay worker, change task queues, etc.
353
+ pub fn with_new_core_worker(&mut self, new_core_worker: Arc<dyn CoreWorker>) {
354
+ self.common.worker = new_core_worker;
355
+ }
356
+
357
+ /// Returns number of currently cached workflows as understood by the SDK. Importantly, this
358
+ /// is not the same as understood by core, though they *should* always be in sync.
359
+ pub fn cached_workflows(&self) -> usize {
360
+ self.workflow_half.workflows.borrow().len()
361
+ }
362
+
363
+ fn split_apart(
364
+ &mut self,
365
+ ) -> (
366
+ &mut CommonWorker,
367
+ &mut WorkflowHalf,
368
+ &mut ActivityHalf,
369
+ &mut Option<AppData>,
370
+ ) {
371
+ (
372
+ &mut self.common,
373
+ &mut self.workflow_half,
374
+ &mut self.activity_half,
375
+ &mut self.app_data,
376
+ )
377
+ }
378
+ }
379
+
380
+ impl WorkflowHalf {
381
+ fn workflow_activation_handler(
382
+ &self,
383
+ common: &CommonWorker,
384
+ shutdown_token: CancellationToken,
385
+ activation: WorkflowActivation,
386
+ completions_tx: &UnboundedSender<WorkflowActivationCompletion>,
387
+ ) -> Result<
388
+ Option<WorkflowFutureHandle<impl Future<Output = Result<WorkflowResult<()>, JoinError>>>>,
389
+ anyhow::Error,
390
+ > {
391
+ let mut res = None;
392
+ let run_id = activation.run_id.clone();
393
+
394
+ // If the activation is to start a workflow, create a new workflow driver for it,
395
+ // using the function associated with that workflow id
396
+ if let Some(WorkflowActivationJob {
397
+ variant: Some(Variant::StartWorkflow(sw)),
398
+ }) = activation.jobs.get(0)
399
+ {
400
+ let workflow_type = &sw.workflow_type;
401
+ let wf_fns_borrow = self.workflow_fns.borrow();
402
+ let wf_function = wf_fns_borrow
403
+ .get(workflow_type)
404
+ .ok_or_else(|| anyhow!("Workflow type {workflow_type} not found"))?;
405
+
406
+ let (wff, activations) = wf_function.start_workflow(
407
+ common.worker.get_config().namespace.clone(),
408
+ common.task_queue.clone(),
409
+ // NOTE: Don't clone args if this gets ported to be a non-test rust worker
410
+ sw.arguments.clone(),
411
+ completions_tx.clone(),
412
+ );
413
+ let jh = tokio::spawn(async move {
414
+ tokio::select! {
415
+ r = wff => r,
416
+ // TODO: This probably shouldn't abort early, as it could cause an in-progress
417
+ // complete to abort. Send synthetic remove activation
418
+ _ = shutdown_token.cancelled() => {
419
+ Ok(WfExitValue::Evicted)
420
+ }
421
+ }
422
+ });
423
+ res = Some(WorkflowFutureHandle {
424
+ join_handle: jh,
425
+ run_id: run_id.clone(),
426
+ });
427
+ self.workflows.borrow_mut().insert(
428
+ run_id.clone(),
429
+ WorkflowData {
430
+ activation_chan: activations,
431
+ },
432
+ );
433
+ }
434
+
435
+ // The activation is expected to apply to some workflow we know about. Use it to
436
+ // unblock things and advance the workflow.
437
+ if let Some(dat) = self.workflows.borrow_mut().get_mut(&run_id) {
438
+ dat.activation_chan
439
+ .send(activation)
440
+ .expect("Workflow should exist if we're sending it an activation");
441
+ } else {
442
+ bail!(
443
+ "Got activation {:?} for unknown workflow {}",
444
+ activation,
445
+ run_id
446
+ );
447
+ };
448
+
449
+ Ok(res)
450
+ }
451
+ }
452
+
453
+ impl ActivityHalf {
454
+ /// Spawns off a task to handle the provided activity task
455
+ fn activity_task_handler(
456
+ &mut self,
457
+ worker: Arc<dyn CoreWorker>,
458
+ app_data: Arc<AppData>,
459
+ task_queue: String,
460
+ activity: ActivityTask,
461
+ ) -> Result<(), anyhow::Error> {
462
+ match activity.variant {
463
+ Some(activity_task::Variant::Start(start)) => {
464
+ let act_fn = self
465
+ .activity_fns
466
+ .get(&start.activity_type)
467
+ .ok_or_else(|| {
468
+ anyhow!(
469
+ "No function registered for activity type {}",
470
+ start.activity_type
471
+ )
472
+ })?
473
+ .clone();
474
+ let ct = CancellationToken::new();
475
+ let task_token = activity.task_token;
476
+ self.task_tokens_to_cancels
477
+ .insert(task_token.clone().into(), ct.clone());
478
+
479
+ let (ctx, arg) = ActContext::new(
480
+ worker.clone(),
481
+ app_data,
482
+ ct,
483
+ task_queue,
484
+ task_token.clone(),
485
+ start,
486
+ );
487
+ tokio::spawn(async move {
488
+ let output = (act_fn.act_func)(ctx, arg).await;
489
+ let result = match output {
490
+ Ok(ActExitValue::Normal(p)) => ActivityExecutionResult::ok(p),
491
+ Ok(ActExitValue::WillCompleteAsync) => {
492
+ ActivityExecutionResult::will_complete_async()
493
+ }
494
+ Err(err) => match err.downcast::<ActivityCancelledError>() {
495
+ Ok(ce) => ActivityExecutionResult::cancel_from_details(ce.details),
496
+ Err(other_err) => ActivityExecutionResult::fail(other_err.into()),
497
+ },
498
+ };
499
+ worker
500
+ .complete_activity_task(ActivityTaskCompletion {
501
+ task_token,
502
+ result: Some(result),
503
+ })
504
+ .await?;
505
+ Ok::<_, anyhow::Error>(())
506
+ });
507
+ }
508
+ Some(activity_task::Variant::Cancel(_)) => {
509
+ if let Some(ct) = self.task_tokens_to_cancels.get(&activity.task_token.into()) {
510
+ ct.cancel();
511
+ }
512
+ }
513
+ None => bail!("Undefined activity task variant"),
514
+ }
515
+ Ok(())
516
+ }
517
+ }
518
+
519
+ #[derive(Debug)]
520
+ enum UnblockEvent {
521
+ Timer(u32, TimerResult),
522
+ Activity(u32, Box<ActivityResolution>),
523
+ WorkflowStart(u32, Box<ChildWorkflowStartStatus>),
524
+ WorkflowComplete(u32, Box<ChildWorkflowResult>),
525
+ SignalExternal(u32, Option<Failure>),
526
+ CancelExternal(u32, Option<Failure>),
527
+ }
528
+
529
+ /// Result of awaiting on a timer
530
+ #[derive(Debug, Copy, Clone)]
531
+ pub enum TimerResult {
532
+ /// The timer was cancelled
533
+ Cancelled,
534
+ /// The timer elapsed and fired
535
+ Fired,
536
+ }
537
+
538
+ /// Successful result of sending a signal to an external workflow
539
+ pub struct SignalExternalOk;
540
+ /// Result of awaiting on sending a signal to an external workflow
541
+ pub type SignalExternalWfResult = Result<SignalExternalOk, Failure>;
542
+
543
+ /// Successful result of sending a cancel request to an external workflow
544
+ pub struct CancelExternalOk;
545
+ /// Result of awaiting on sending a cancel request to an external workflow
546
+ pub type CancelExternalWfResult = Result<CancelExternalOk, Failure>;
547
+
548
+ trait Unblockable {
549
+ type OtherDat;
550
+
551
+ fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self;
552
+ }
553
+
554
+ impl Unblockable for TimerResult {
555
+ type OtherDat = ();
556
+ fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
557
+ match ue {
558
+ UnblockEvent::Timer(_, result) => result,
559
+ _ => panic!("Invalid unblock event for timer"),
560
+ }
561
+ }
562
+ }
563
+
564
+ impl Unblockable for ActivityResolution {
565
+ type OtherDat = ();
566
+ fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
567
+ match ue {
568
+ UnblockEvent::Activity(_, result) => *result,
569
+ _ => panic!("Invalid unblock event for activity"),
570
+ }
571
+ }
572
+ }
573
+
574
+ impl Unblockable for PendingChildWorkflow {
575
+ // Other data here is workflow id
576
+ type OtherDat = ChildWfCommon;
577
+ fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self {
578
+ match ue {
579
+ UnblockEvent::WorkflowStart(_, result) => Self {
580
+ status: *result,
581
+ common: od,
582
+ },
583
+ _ => panic!("Invalid unblock event for child workflow start"),
584
+ }
585
+ }
586
+ }
587
+
588
+ impl Unblockable for ChildWorkflowResult {
589
+ type OtherDat = ();
590
+ fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
591
+ match ue {
592
+ UnblockEvent::WorkflowComplete(_, result) => *result,
593
+ _ => panic!("Invalid unblock event for child workflow complete"),
594
+ }
595
+ }
596
+ }
597
+
598
+ impl Unblockable for SignalExternalWfResult {
599
+ type OtherDat = ();
600
+ fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
601
+ match ue {
602
+ UnblockEvent::SignalExternal(_, maybefail) => {
603
+ maybefail.map_or(Ok(SignalExternalOk), Err)
604
+ }
605
+ _ => panic!("Invalid unblock event for signal external workflow result"),
606
+ }
607
+ }
608
+ }
609
+
610
+ impl Unblockable for CancelExternalWfResult {
611
+ type OtherDat = ();
612
+ fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
613
+ match ue {
614
+ UnblockEvent::CancelExternal(_, maybefail) => {
615
+ maybefail.map_or(Ok(CancelExternalOk), Err)
616
+ }
617
+ _ => panic!("Invalid unblock event for signal external workflow result"),
618
+ }
619
+ }
620
+ }
621
+
622
+ /// Identifier for cancellable operations
623
+ #[derive(Debug, Clone)]
624
+ pub enum CancellableID {
625
+ /// Timer sequence number
626
+ Timer(u32),
627
+ /// Activity sequence number
628
+ Activity(u32),
629
+ /// Activity sequence number
630
+ LocalActivity(u32),
631
+ /// Start child sequence number
632
+ ChildWorkflow(u32),
633
+ /// Signal workflow
634
+ SignalExternalWorkflow(u32),
635
+ /// An external workflow identifier as may have been created by a started child workflow
636
+ ExternalWorkflow {
637
+ /// Sequence number which will be used for the cancel command
638
+ seqnum: u32,
639
+ /// Identifying information about the workflow to be cancelled
640
+ execution: NamespacedWorkflowExecution,
641
+ /// Set to true if this workflow is a child of the issuing workflow
642
+ only_child: bool,
643
+ },
644
+ }
645
+
646
+ #[derive(derive_more::From)]
647
+ #[allow(clippy::large_enum_variant)]
648
+ enum RustWfCmd {
649
+ #[from(ignore)]
650
+ Cancel(CancellableID),
651
+ ForceWFTFailure(anyhow::Error),
652
+ NewCmd(CommandCreateRequest),
653
+ NewNonblockingCmd(workflow_command::Variant),
654
+ SubscribeChildWorkflowCompletion(CommandSubscribeChildWorkflowCompletion),
655
+ SubscribeSignal(String, UnboundedSender<SignalData>),
656
+ }
657
+
658
+ struct CommandCreateRequest {
659
+ cmd: workflow_command::Variant,
660
+ unblocker: oneshot::Sender<UnblockEvent>,
661
+ }
662
+
663
+ struct CommandSubscribeChildWorkflowCompletion {
664
+ seq: u32,
665
+ unblocker: oneshot::Sender<UnblockEvent>,
666
+ }
667
+
668
+ type WfFunc = dyn Fn(WfContext) -> BoxFuture<'static, WorkflowResult<()>> + Send + Sync + 'static;
669
+
670
+ /// The user's async function / workflow code
671
+ pub struct WorkflowFunction {
672
+ wf_func: Box<WfFunc>,
673
+ }
674
+
675
+ impl<F, Fut> From<F> for WorkflowFunction
676
+ where
677
+ F: Fn(WfContext) -> Fut + Send + Sync + 'static,
678
+ Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
679
+ {
680
+ fn from(wf_func: F) -> Self {
681
+ Self::new(wf_func)
682
+ }
683
+ }
684
+
685
+ impl WorkflowFunction {
686
+ /// Build a workflow function from a closure or function pointer which accepts a [WfContext]
687
+ pub fn new<F, Fut>(wf_func: F) -> Self
688
+ where
689
+ F: Fn(WfContext) -> Fut + Send + Sync + 'static,
690
+ Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
691
+ {
692
+ Self {
693
+ wf_func: Box::new(move |ctx: WfContext| wf_func(ctx).boxed()),
694
+ }
695
+ }
696
+ }
697
+
698
+ /// The result of running a workflow
699
+ pub type WorkflowResult<T> = Result<WfExitValue<T>, anyhow::Error>;
700
+
701
+ /// Workflow functions may return these values when exiting
702
+ #[derive(Debug, derive_more::From)]
703
+ pub enum WfExitValue<T: Debug> {
704
+ /// Continue the workflow as a new execution
705
+ #[from(ignore)]
706
+ ContinueAsNew(Box<ContinueAsNewWorkflowExecution>),
707
+ /// Confirm the workflow was cancelled (can be automatic in a more advanced iteration)
708
+ #[from(ignore)]
709
+ Cancelled,
710
+ /// The run was evicted
711
+ #[from(ignore)]
712
+ Evicted,
713
+ /// Finish with a result
714
+ Normal(T),
715
+ }
716
+
717
+ impl<T: Debug> WfExitValue<T> {
718
+ /// Construct a [WfExitValue::ContinueAsNew] variant (handles boxing)
719
+ pub fn continue_as_new(can: ContinueAsNewWorkflowExecution) -> Self {
720
+ Self::ContinueAsNew(Box::new(can))
721
+ }
722
+ }
723
+
724
+ /// Activity functions may return these values when exiting
725
+ #[derive(derive_more::From)]
726
+ pub enum ActExitValue<T: Debug> {
727
+ /// Completion requires an asynchronous callback
728
+ #[from(ignore)]
729
+ WillCompleteAsync,
730
+ /// Finish with a result
731
+ Normal(T),
732
+ }
733
+
734
+ type BoxActFn = Arc<
735
+ dyn Fn(ActContext, Payload) -> BoxFuture<'static, Result<ActExitValue<Payload>, anyhow::Error>>
736
+ + Send
737
+ + Sync,
738
+ >;
739
+
740
+ /// Container for user-defined activity functions
741
+ #[derive(Clone)]
742
+ pub struct ActivityFunction {
743
+ act_func: BoxActFn,
744
+ }
745
+
746
+ /// Return this error to indicate your activity is cancelling
747
+ #[derive(Debug, Default)]
748
+ pub struct ActivityCancelledError {
749
+ details: Option<Payload>,
750
+ }
751
+ impl std::error::Error for ActivityCancelledError {}
752
+ impl Display for ActivityCancelledError {
753
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
754
+ write!(f, "Activity cancelled")
755
+ }
756
+ }
757
+
758
+ /// Closures / functions which can be turned into activity functions implement this trait
759
+ pub trait IntoActivityFunc<Args, Res, Out> {
760
+ /// Consume the closure or fn pointer and turned it into a boxed activity function
761
+ fn into_activity_fn(self) -> BoxActFn;
762
+ }
763
+
764
+ impl<A, Rf, R, O, F> IntoActivityFunc<A, Rf, O> for F
765
+ where
766
+ F: (Fn(ActContext, A) -> Rf) + Sync + Send + 'static,
767
+ A: FromJsonPayloadExt + Send,
768
+ Rf: Future<Output = Result<R, anyhow::Error>> + Send + 'static,
769
+ R: Into<ActExitValue<O>>,
770
+ O: AsJsonPayloadExt + Debug,
771
+ {
772
+ fn into_activity_fn(self) -> BoxActFn {
773
+ let wrapper = move |ctx: ActContext, input: Payload| {
774
+ // Some minor gymnastics are required to avoid needing to clone the function
775
+ match A::from_json_payload(&input) {
776
+ Ok(deser) => (self)(ctx, deser)
777
+ .map(|r| {
778
+ r.and_then(|r| {
779
+ let exit_val: ActExitValue<O> = r.into();
780
+ Ok(match exit_val {
781
+ ActExitValue::WillCompleteAsync => ActExitValue::WillCompleteAsync,
782
+ ActExitValue::Normal(x) => {
783
+ ActExitValue::Normal(x.as_json_payload()?)
784
+ }
785
+ })
786
+ })
787
+ })
788
+ .boxed(),
789
+ Err(e) => async move { Err(e.into()) }.boxed(),
790
+ }
791
+ };
792
+ Arc::new(wrapper)
793
+ }
794
+ }