temporalio 0.0.0 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (327) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +301 -0
  3. data/bridge/Cargo.lock +2888 -0
  4. data/bridge/Cargo.toml +27 -0
  5. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  6. data/bridge/sdk-core/Cargo.lock +2606 -0
  7. data/bridge/sdk-core/Cargo.toml +2 -0
  8. data/bridge/sdk-core/LICENSE.txt +23 -0
  9. data/bridge/sdk-core/README.md +104 -0
  10. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  11. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  13. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  14. data/bridge/sdk-core/client/Cargo.toml +40 -0
  15. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  16. data/bridge/sdk-core/client/src/lib.rs +1286 -0
  17. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  18. data/bridge/sdk-core/client/src/raw.rs +932 -0
  19. data/bridge/sdk-core/client/src/retry.rs +751 -0
  20. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  21. data/bridge/sdk-core/core/Cargo.toml +116 -0
  22. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  23. data/bridge/sdk-core/core/benches/workflow_replay.rs +76 -0
  24. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  25. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -0
  26. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  27. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  28. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +925 -0
  29. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  30. data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -0
  31. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  32. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  33. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  34. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2090 -0
  35. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  36. data/bridge/sdk-core/core/src/lib.rs +282 -0
  37. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  38. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  39. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  40. data/bridge/sdk-core/core/src/replay/mod.rs +215 -0
  41. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  42. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  43. data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
  44. data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
  45. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
  46. data/bridge/sdk-core/core/src/test_help/mod.rs +889 -0
  47. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  48. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1048 -0
  49. data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
  50. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  51. data/bridge/sdk-core/core/src/worker/client.rs +373 -0
  52. data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
  53. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  54. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
  55. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
  60. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1200 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +655 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +985 -0
  80. data/bridge/sdk-core/core-api/Cargo.toml +32 -0
  81. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  82. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  83. data/bridge/sdk-core/core-api/src/lib.rs +109 -0
  84. data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
  85. data/bridge/sdk-core/core-api/src/worker.rs +148 -0
  86. data/bridge/sdk-core/etc/deps.svg +162 -0
  87. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  88. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  89. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  90. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  91. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  92. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  93. data/bridge/sdk-core/fsm/README.md +3 -0
  94. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  95. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  96. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  97. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  98. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  99. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  100. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  115. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  116. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  117. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  118. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  119. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  120. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  121. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  122. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  123. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  124. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  125. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  126. data/bridge/sdk-core/protos/api_upstream/buf.yaml +9 -0
  127. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  128. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  129. data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
  130. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  131. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  132. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +47 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +56 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +40 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +758 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +121 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +379 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -0
  164. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  165. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  166. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +263 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  174. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  175. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  176. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  179. data/bridge/sdk-core/rustfmt.toml +1 -0
  180. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  181. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  182. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  183. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  184. data/bridge/sdk-core/sdk/src/interceptors.rs +50 -0
  185. data/bridge/sdk-core/sdk/src/lib.rs +794 -0
  186. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  187. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  188. data/bridge/sdk-core/sdk/src/workflow_context.rs +694 -0
  189. data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -0
  190. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  191. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  192. data/bridge/sdk-core/sdk-core-protos/build.rs +107 -0
  193. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  194. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
  195. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  196. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  199. data/bridge/sdk-core/test-utils/Cargo.toml +36 -0
  200. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  201. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  202. data/bridge/sdk-core/test-utils/src/lib.rs +650 -0
  203. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  204. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  205. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +221 -0
  206. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  207. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -0
  208. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  209. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  210. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  211. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  212. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +788 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +223 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +597 -0
  227. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  228. data/bridge/sdk-core/tests/main.rs +113 -0
  229. data/bridge/sdk-core/tests/runner.rs +93 -0
  230. data/bridge/src/connection.rs +186 -0
  231. data/bridge/src/lib.rs +239 -0
  232. data/bridge/src/runtime.rs +54 -0
  233. data/bridge/src/worker.rs +124 -0
  234. data/ext/Rakefile +9 -0
  235. data/lib/bridge.so +0 -0
  236. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  237. data/lib/gen/temporal/api/batch/v1/message_pb.rb +50 -0
  238. data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
  239. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  240. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
  241. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
  242. data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
  243. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
  244. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
  245. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -0
  246. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  247. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  248. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  249. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  250. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  251. data/lib/gen/temporal/api/enums/v1/update_pb.rb +23 -0
  252. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  253. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  254. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  255. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  256. data/lib/gen/temporal/api/history/v1/message_pb.rb +490 -0
  257. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
  258. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  259. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -0
  260. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  261. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  262. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  263. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +149 -0
  264. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  265. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  266. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
  267. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -0
  268. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  269. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  270. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  271. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  272. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  273. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  274. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  275. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  276. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +165 -0
  277. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
  278. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  279. data/lib/temporalio/activity/context.rb +97 -0
  280. data/lib/temporalio/activity/info.rb +67 -0
  281. data/lib/temporalio/activity.rb +85 -0
  282. data/lib/temporalio/bridge/error.rb +8 -0
  283. data/lib/temporalio/bridge.rb +14 -0
  284. data/lib/temporalio/client/implementation.rb +340 -0
  285. data/lib/temporalio/client/workflow_handle.rb +243 -0
  286. data/lib/temporalio/client.rb +131 -0
  287. data/lib/temporalio/connection.rb +751 -0
  288. data/lib/temporalio/data_converter.rb +191 -0
  289. data/lib/temporalio/error/failure.rb +194 -0
  290. data/lib/temporalio/error/workflow_failure.rb +19 -0
  291. data/lib/temporalio/errors.rb +40 -0
  292. data/lib/temporalio/failure_converter/base.rb +26 -0
  293. data/lib/temporalio/failure_converter/basic.rb +319 -0
  294. data/lib/temporalio/failure_converter.rb +7 -0
  295. data/lib/temporalio/interceptor/chain.rb +28 -0
  296. data/lib/temporalio/interceptor/client.rb +123 -0
  297. data/lib/temporalio/payload_codec/base.rb +32 -0
  298. data/lib/temporalio/payload_converter/base.rb +24 -0
  299. data/lib/temporalio/payload_converter/bytes.rb +27 -0
  300. data/lib/temporalio/payload_converter/composite.rb +49 -0
  301. data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
  302. data/lib/temporalio/payload_converter/json.rb +26 -0
  303. data/lib/temporalio/payload_converter/nil.rb +26 -0
  304. data/lib/temporalio/payload_converter.rb +14 -0
  305. data/lib/temporalio/retry_policy.rb +82 -0
  306. data/lib/temporalio/retry_state.rb +35 -0
  307. data/lib/temporalio/runtime.rb +25 -0
  308. data/lib/temporalio/timeout_type.rb +29 -0
  309. data/lib/temporalio/version.rb +3 -0
  310. data/lib/temporalio/worker/activity_runner.rb +92 -0
  311. data/lib/temporalio/worker/activity_worker.rb +138 -0
  312. data/lib/temporalio/worker/reactor.rb +46 -0
  313. data/lib/temporalio/worker/runner.rb +63 -0
  314. data/lib/temporalio/worker/sync_worker.rb +88 -0
  315. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  316. data/lib/temporalio/worker.rb +198 -0
  317. data/lib/temporalio/workflow/execution_info.rb +54 -0
  318. data/lib/temporalio/workflow/execution_status.rb +36 -0
  319. data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
  320. data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
  321. data/lib/temporalio.rb +12 -1
  322. data/lib/thermite_patch.rb +23 -0
  323. data/temporalio.gemspec +45 -0
  324. metadata +566 -9
  325. data/lib/temporal/version.rb +0 -3
  326. data/lib/temporal.rb +0 -4
  327. data/temporal.gemspec +0 -20
@@ -0,0 +1,1286 @@
1
+ #![warn(missing_docs)] // error if there are missing docs
2
+
3
+ //! This crate contains client implementations that can be used to contact the Temporal service.
4
+ //!
5
+ //! It implements auto-retry behavior and metrics collection.
6
+
7
+ #[macro_use]
8
+ extern crate tracing;
9
+
10
+ mod metrics;
11
+ mod raw;
12
+ mod retry;
13
+ mod workflow_handle;
14
+
15
+ pub use crate::retry::{CallType, RetryClient, RETRYABLE_ERROR_CODES};
16
+ pub use raw::{HealthService, OperatorService, TestService, WorkflowService};
17
+ pub use temporal_sdk_core_protos::temporal::api::{
18
+ filter::v1::{StartTimeFilter, StatusFilter, WorkflowExecutionFilter, WorkflowTypeFilter},
19
+ workflowservice::v1::{
20
+ list_closed_workflow_executions_request::Filters as ListClosedFilters,
21
+ list_open_workflow_executions_request::Filters as ListOpenFilters,
22
+ },
23
+ };
24
+ pub use workflow_handle::{WorkflowExecutionInfo, WorkflowExecutionResult};
25
+
26
+ use crate::{
27
+ metrics::{GrpcMetricSvc, MetricsContext},
28
+ raw::{sealed::RawClientLike, AttachMetricLabels},
29
+ sealed::WfHandleClient,
30
+ workflow_handle::UntypedWorkflowHandle,
31
+ };
32
+ use backoff::{exponential, ExponentialBackoff, SystemClock};
33
+ use http::uri::InvalidUri;
34
+ use once_cell::sync::OnceCell;
35
+ use opentelemetry::metrics::Meter;
36
+ use parking_lot::RwLock;
37
+ use std::{
38
+ collections::HashMap,
39
+ fmt::{Debug, Formatter},
40
+ ops::{Deref, DerefMut},
41
+ str::FromStr,
42
+ sync::Arc,
43
+ time::{Duration, Instant},
44
+ };
45
+ use temporal_sdk_core_protos::{
46
+ coresdk::{workflow_commands::QueryResult, IntoPayloadsExt},
47
+ grpc::health::v1::health_client::HealthClient,
48
+ temporal::api::{
49
+ common::v1::{Header, Payload, Payloads, WorkflowExecution, WorkflowType},
50
+ enums::v1::{TaskQueueKind, WorkflowIdReusePolicy, WorkflowTaskFailedCause},
51
+ failure::v1::Failure,
52
+ operatorservice::v1::operator_service_client::OperatorServiceClient,
53
+ query::v1::WorkflowQuery,
54
+ taskqueue::v1::TaskQueue,
55
+ testservice::v1::test_service_client::TestServiceClient,
56
+ workflowservice::v1::{workflow_service_client::WorkflowServiceClient, *},
57
+ },
58
+ TaskToken,
59
+ };
60
+ use tonic::{
61
+ body::BoxBody,
62
+ client::GrpcService,
63
+ codegen::InterceptedService,
64
+ metadata::{MetadataKey, MetadataValue},
65
+ service::Interceptor,
66
+ transport::{Certificate, Channel, Endpoint, Identity},
67
+ Code, Status,
68
+ };
69
+ use tower::ServiceBuilder;
70
+ use url::Url;
71
+ use uuid::Uuid;
72
+
73
+ static CLIENT_NAME_HEADER_KEY: &str = "client-name";
74
+ static CLIENT_VERSION_HEADER_KEY: &str = "client-version";
75
+ /// These must match the gRPC method names, not the snake case versions that exist in the Rust code.
76
+ static LONG_POLL_METHOD_NAMES: [&str; 2] = ["PollWorkflowTaskQueue", "PollActivityTaskQueue"];
77
+ /// The server times out polls after 60 seconds. Set our timeout to be slightly beyond that.
78
+ const LONG_POLL_TIMEOUT: Duration = Duration::from_secs(70);
79
+ const OTHER_CALL_TIMEOUT: Duration = Duration::from_secs(30);
80
+
81
+ type Result<T, E = tonic::Status> = std::result::Result<T, E>;
82
+
83
+ /// Options for the connection to the temporal server. Construct with [ClientOptionsBuilder]
84
+ #[derive(Clone, Debug, derive_builder::Builder)]
85
+ #[non_exhaustive]
86
+ pub struct ClientOptions {
87
+ /// The URL of the Temporal server to connect to
88
+ #[builder(setter(into))]
89
+ pub target_url: Url,
90
+
91
+ /// The name of the SDK being implemented on top of core. Is set as `client-name` header in
92
+ /// all RPC calls
93
+ #[builder(setter(into))]
94
+ pub client_name: String,
95
+
96
+ /// The version of the SDK being implemented on top of core. Is set as `client-version` header
97
+ /// in all RPC calls. The server decides if the client is supported based on this.
98
+ #[builder(setter(into))]
99
+ pub client_version: String,
100
+
101
+ /// A human-readable string that can identify this process. Defaults to empty string.
102
+ #[builder(default)]
103
+ pub identity: String,
104
+
105
+ /// If specified, use TLS as configured by the [TlsConfig] struct. If this is set core will
106
+ /// attempt to use TLS when connecting to the Temporal server. Lang SDK is expected to pass any
107
+ /// certs or keys as bytes, loading them from disk itself if needed.
108
+ #[builder(setter(strip_option), default)]
109
+ pub tls_cfg: Option<TlsConfig>,
110
+
111
+ /// Retry configuration for the server client. Default is [RetryConfig::default]
112
+ #[builder(default)]
113
+ pub retry_config: RetryConfig,
114
+ }
115
+
116
+ /// Configuration options for TLS
117
+ #[derive(Clone, Debug, Default)]
118
+ pub struct TlsConfig {
119
+ /// Bytes representing the root CA certificate used by the server. If not set, and the server's
120
+ /// cert is issued by someone the operating system trusts, verification will still work (ex:
121
+ /// Cloud offering).
122
+ pub server_root_ca_cert: Option<Vec<u8>>,
123
+ /// Sets the domain name against which to verify the server's TLS certificate. If not provided,
124
+ /// the domain name will be extracted from the URL used to connect.
125
+ pub domain: Option<String>,
126
+ /// TLS info for the client. If specified, core will attempt to use mTLS.
127
+ pub client_tls_config: Option<ClientTlsConfig>,
128
+ }
129
+
130
+ /// If using mTLS, both the client cert and private key must be specified, this contains them.
131
+ #[derive(Clone)]
132
+ pub struct ClientTlsConfig {
133
+ /// The certificate for this client
134
+ pub client_cert: Vec<u8>,
135
+ /// The private key for this client
136
+ pub client_private_key: Vec<u8>,
137
+ }
138
+
139
+ /// Configuration for retrying requests to the server
140
+ #[derive(Clone, Debug)]
141
+ pub struct RetryConfig {
142
+ /// initial wait time before the first retry.
143
+ pub initial_interval: Duration,
144
+ /// randomization jitter that is used as a multiplier for the current retry interval
145
+ /// and is added or subtracted from the interval length.
146
+ pub randomization_factor: f64,
147
+ /// rate at which retry time should be increased, until it reaches max_interval.
148
+ pub multiplier: f64,
149
+ /// maximum amount of time to wait between retries.
150
+ pub max_interval: Duration,
151
+ /// maximum total amount of time requests should be retried for, if None is set then no limit
152
+ /// will be used.
153
+ pub max_elapsed_time: Option<Duration>,
154
+ /// maximum number of retry attempts.
155
+ pub max_retries: usize,
156
+ }
157
+
158
+ impl Default for RetryConfig {
159
+ fn default() -> Self {
160
+ Self {
161
+ initial_interval: Duration::from_millis(100), // 100 ms wait by default.
162
+ randomization_factor: 0.2, // +-20% jitter.
163
+ multiplier: 1.5, // each next retry delay will increase by 50%
164
+ max_interval: Duration::from_secs(5), // until it reaches 5 seconds.
165
+ max_elapsed_time: Some(Duration::from_secs(10)), // 10 seconds total allocated time for all retries.
166
+ max_retries: 10,
167
+ }
168
+ }
169
+ }
170
+
171
+ impl RetryConfig {
172
+ pub(crate) const fn poll_retry_policy() -> Self {
173
+ Self {
174
+ initial_interval: Duration::from_millis(200),
175
+ randomization_factor: 0.2,
176
+ multiplier: 2.0,
177
+ max_interval: Duration::from_secs(10),
178
+ max_elapsed_time: None,
179
+ max_retries: 0,
180
+ }
181
+ }
182
+
183
+ pub(crate) const fn throttle_retry_policy() -> Self {
184
+ Self {
185
+ initial_interval: Duration::from_secs(1),
186
+ randomization_factor: 0.2,
187
+ multiplier: 2.0,
188
+ max_interval: Duration::from_secs(10),
189
+ max_elapsed_time: None,
190
+ max_retries: 0,
191
+ }
192
+ }
193
+
194
+ pub(crate) fn into_exp_backoff<C>(self, clock: C) -> exponential::ExponentialBackoff<C> {
195
+ exponential::ExponentialBackoff {
196
+ current_interval: self.initial_interval,
197
+ initial_interval: self.initial_interval,
198
+ randomization_factor: self.randomization_factor,
199
+ multiplier: self.multiplier,
200
+ max_interval: self.max_interval,
201
+ max_elapsed_time: self.max_elapsed_time,
202
+ clock,
203
+ start_time: Instant::now(),
204
+ }
205
+ }
206
+ }
207
+
208
+ impl From<RetryConfig> for ExponentialBackoff {
209
+ fn from(c: RetryConfig) -> Self {
210
+ c.into_exp_backoff(SystemClock::default())
211
+ }
212
+ }
213
+
214
+ impl Debug for ClientTlsConfig {
215
+ // Intentionally omit details here since they could leak a key if ever printed
216
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
217
+ write!(f, "ClientTlsConfig(..)")
218
+ }
219
+ }
220
+
221
+ /// Errors thrown while attempting to establish a connection to the server
222
+ #[derive(thiserror::Error, Debug)]
223
+ pub enum ClientInitError {
224
+ /// Invalid URI. Configuration error, fatal.
225
+ #[error("Invalid URI: {0:?}")]
226
+ InvalidUri(#[from] InvalidUri),
227
+ /// Server connection error. Crashing and restarting the worker is likely best.
228
+ #[error("Server connection error: {0:?}")]
229
+ TonicTransportError(#[from] tonic::transport::Error),
230
+ /// We couldn't successfully make the `get_system_info` call at connection time to establish
231
+ /// server capabilities / verify server is responding.
232
+ #[error("`get_system_info` call error after connection: {0:?}")]
233
+ SystemInfoCallError(tonic::Status),
234
+ }
235
+
236
+ /// A client with [ClientOptions] attached, which can be passed to initialize workers,
237
+ /// or can be used directly. Is cheap to clone.
238
+ #[derive(Clone, Debug)]
239
+ pub struct ConfiguredClient<C> {
240
+ client: C,
241
+ options: Arc<ClientOptions>,
242
+ headers: Arc<RwLock<HashMap<String, String>>>,
243
+ /// Capabilities as read from the `get_system_info` RPC call made on client connection
244
+ capabilities: Option<get_system_info_response::Capabilities>,
245
+ }
246
+
247
+ impl<C> ConfiguredClient<C> {
248
+ /// Set HTTP request headers overwriting previous headers
249
+ pub fn set_headers(&self, headers: HashMap<String, String>) {
250
+ let mut guard = self.headers.write();
251
+ *guard = headers;
252
+ }
253
+
254
+ /// Returns the options the client is configured with
255
+ pub fn options(&self) -> &ClientOptions {
256
+ &self.options
257
+ }
258
+
259
+ /// Returns the server capabilities we (may have) learned about when establishing an initial
260
+ /// connection
261
+ pub fn capabilities(&self) -> Option<&get_system_info_response::Capabilities> {
262
+ self.capabilities.as_ref()
263
+ }
264
+ }
265
+
266
+ // The configured client is effectively a "smart" (dumb) pointer
267
+ impl<C> Deref for ConfiguredClient<C> {
268
+ type Target = C;
269
+
270
+ fn deref(&self) -> &Self::Target {
271
+ &self.client
272
+ }
273
+ }
274
+ impl<C> DerefMut for ConfiguredClient<C> {
275
+ fn deref_mut(&mut self) -> &mut Self::Target {
276
+ &mut self.client
277
+ }
278
+ }
279
+
280
+ impl ClientOptions {
281
+ /// Attempt to establish a connection to the Temporal server in a specific namespace. The
282
+ /// returned client is bound to that namespace.
283
+ pub async fn connect(
284
+ &self,
285
+ namespace: impl Into<String>,
286
+ metrics_meter: Option<&Meter>,
287
+ headers: Option<Arc<RwLock<HashMap<String, String>>>>,
288
+ ) -> Result<RetryClient<Client>, ClientInitError> {
289
+ let client = self
290
+ .connect_no_namespace(metrics_meter, headers)
291
+ .await?
292
+ .into_inner();
293
+ let client = Client::new(client, namespace.into());
294
+ let retry_client = RetryClient::new(client, self.retry_config.clone());
295
+ Ok(retry_client)
296
+ }
297
+
298
+ /// Attempt to establish a connection to the Temporal server and return a gRPC client which is
299
+ /// intercepted with retry, default headers functionality, and metrics if provided.
300
+ ///
301
+ /// See [RetryClient] for more
302
+ pub async fn connect_no_namespace(
303
+ &self,
304
+ metrics_meter: Option<&Meter>,
305
+ headers: Option<Arc<RwLock<HashMap<String, String>>>>,
306
+ ) -> Result<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>, ClientInitError>
307
+ {
308
+ let channel = Channel::from_shared(self.target_url.to_string())?;
309
+ let channel = self.add_tls_to_channel(channel).await?;
310
+ let channel = channel.connect().await?;
311
+ let service = ServiceBuilder::new()
312
+ .layer_fn(|channel| GrpcMetricSvc {
313
+ inner: channel,
314
+ metrics: metrics_meter.map(|mm| MetricsContext::new(vec![], mm)),
315
+ })
316
+ .service(channel);
317
+ let headers = headers.unwrap_or_default();
318
+ let interceptor = ServiceCallInterceptor {
319
+ opts: self.clone(),
320
+ headers: headers.clone(),
321
+ };
322
+ let svc = InterceptedService::new(service, interceptor);
323
+
324
+ let mut client = ConfiguredClient {
325
+ headers,
326
+ client: TemporalServiceClient::new(svc),
327
+ options: Arc::new(self.clone()),
328
+ capabilities: None,
329
+ };
330
+ match client
331
+ .get_system_info(GetSystemInfoRequest::default())
332
+ .await
333
+ {
334
+ Ok(sysinfo) => {
335
+ client.capabilities = sysinfo.into_inner().capabilities;
336
+ }
337
+ Err(status) => match status.code() {
338
+ Code::Unimplemented => {}
339
+ _ => return Err(ClientInitError::SystemInfoCallError(status)),
340
+ },
341
+ };
342
+ Ok(RetryClient::new(client, self.retry_config.clone()))
343
+ }
344
+
345
+ /// If TLS is configured, set the appropriate options on the provided channel and return it.
346
+ /// Passes it through if TLS options not set.
347
+ async fn add_tls_to_channel(
348
+ &self,
349
+ channel: Endpoint,
350
+ ) -> Result<Endpoint, tonic::transport::Error> {
351
+ if let Some(tls_cfg) = &self.tls_cfg {
352
+ let mut tls = tonic::transport::ClientTlsConfig::new();
353
+
354
+ if let Some(root_cert) = &tls_cfg.server_root_ca_cert {
355
+ let server_root_ca_cert = Certificate::from_pem(root_cert);
356
+ tls = tls.ca_certificate(server_root_ca_cert);
357
+ }
358
+
359
+ if let Some(domain) = &tls_cfg.domain {
360
+ tls = tls.domain_name(domain);
361
+ }
362
+
363
+ if let Some(client_opts) = &tls_cfg.client_tls_config {
364
+ let client_identity =
365
+ Identity::from_pem(&client_opts.client_cert, &client_opts.client_private_key);
366
+ tls = tls.identity(client_identity);
367
+ }
368
+
369
+ return channel.tls_config(tls);
370
+ }
371
+ Ok(channel)
372
+ }
373
+ }
374
+
375
+ /// Interceptor which attaches common metadata (like "client-name") to every outgoing call
376
+ #[derive(Clone)]
377
+ pub struct ServiceCallInterceptor {
378
+ opts: ClientOptions,
379
+ /// Only accessed as a reader
380
+ headers: Arc<RwLock<HashMap<String, String>>>,
381
+ }
382
+
383
+ impl Interceptor for ServiceCallInterceptor {
384
+ /// This function will get called on each outbound request. Returning a `Status` here will
385
+ /// cancel the request and have that status returned to the caller.
386
+ fn call(&mut self, mut request: tonic::Request<()>) -> Result<tonic::Request<()>, Status> {
387
+ let metadata = request.metadata_mut();
388
+ if !metadata.contains_key(CLIENT_NAME_HEADER_KEY) {
389
+ metadata.insert(
390
+ CLIENT_NAME_HEADER_KEY,
391
+ self.opts
392
+ .client_name
393
+ .parse()
394
+ .unwrap_or_else(|_| MetadataValue::from_static("")),
395
+ );
396
+ }
397
+ if !metadata.contains_key(CLIENT_VERSION_HEADER_KEY) {
398
+ metadata.insert(
399
+ CLIENT_VERSION_HEADER_KEY,
400
+ self.opts
401
+ .client_version
402
+ .parse()
403
+ .unwrap_or_else(|_| MetadataValue::from_static("")),
404
+ );
405
+ }
406
+ let headers = &*self.headers.read();
407
+ for (k, v) in headers {
408
+ if metadata.contains_key(k) {
409
+ // Don't overwrite per-request specified headers
410
+ continue;
411
+ }
412
+ if let (Ok(k), Ok(v)) = (MetadataKey::from_str(k), v.parse()) {
413
+ metadata.insert(k, v);
414
+ }
415
+ }
416
+ if !metadata.contains_key("grpc-timeout") {
417
+ request.set_timeout(OTHER_CALL_TIMEOUT);
418
+ }
419
+
420
+ Ok(request)
421
+ }
422
+ }
423
+
424
+ /// Aggregates various services exposed by the Temporal server
425
+ #[derive(Debug, Clone)]
426
+ pub struct TemporalServiceClient<T> {
427
+ svc: T,
428
+ workflow_svc_client: OnceCell<WorkflowServiceClient<T>>,
429
+ operator_svc_client: OnceCell<OperatorServiceClient<T>>,
430
+ test_svc_client: OnceCell<TestServiceClient<T>>,
431
+ health_svc_client: OnceCell<HealthClient<T>>,
432
+ }
433
+ impl<T> TemporalServiceClient<T>
434
+ where
435
+ T: Clone,
436
+ T: GrpcService<BoxBody> + Send + Clone + 'static,
437
+ T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
438
+ T::Error: Into<tonic::codegen::StdError>,
439
+ <T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
440
+ {
441
+ fn new(svc: T) -> Self {
442
+ Self {
443
+ svc,
444
+ workflow_svc_client: OnceCell::new(),
445
+ operator_svc_client: OnceCell::new(),
446
+ test_svc_client: OnceCell::new(),
447
+ health_svc_client: OnceCell::new(),
448
+ }
449
+ }
450
+ /// Get the underlying workflow service client
451
+ pub fn workflow_svc(&self) -> &WorkflowServiceClient<T> {
452
+ self.workflow_svc_client
453
+ .get_or_init(|| WorkflowServiceClient::new(self.svc.clone()))
454
+ }
455
+ /// Get the underlying operator service client
456
+ pub fn operator_svc(&self) -> &OperatorServiceClient<T> {
457
+ self.operator_svc_client
458
+ .get_or_init(|| OperatorServiceClient::new(self.svc.clone()))
459
+ }
460
+ /// Get the underlying test service client
461
+ pub fn test_svc(&self) -> &TestServiceClient<T> {
462
+ self.test_svc_client
463
+ .get_or_init(|| TestServiceClient::new(self.svc.clone()))
464
+ }
465
+ /// Get the underlying health service client
466
+ pub fn health_svc(&self) -> &HealthClient<T> {
467
+ self.health_svc_client
468
+ .get_or_init(|| HealthClient::new(self.svc.clone()))
469
+ }
470
+ /// Get the underlying workflow service client mutably
471
+ pub fn workflow_svc_mut(&mut self) -> &mut WorkflowServiceClient<T> {
472
+ let _ = self.workflow_svc();
473
+ self.workflow_svc_client.get_mut().unwrap()
474
+ }
475
+ /// Get the underlying operator service client mutably
476
+ pub fn operator_svc_mut(&mut self) -> &mut OperatorServiceClient<T> {
477
+ let _ = self.operator_svc();
478
+ self.operator_svc_client.get_mut().unwrap()
479
+ }
480
+ /// Get the underlying test service client mutably
481
+ pub fn test_svc_mut(&mut self) -> &mut TestServiceClient<T> {
482
+ let _ = self.test_svc();
483
+ self.test_svc_client.get_mut().unwrap()
484
+ }
485
+ /// Get the underlying health service client mutably
486
+ pub fn health_svc_mut(&mut self) -> &mut HealthClient<T> {
487
+ let _ = self.health_svc();
488
+ self.health_svc_client.get_mut().unwrap()
489
+ }
490
+ }
491
+ /// A [WorkflowServiceClient] with the default interceptors attached.
492
+ pub type WorkflowServiceClientWithMetrics = WorkflowServiceClient<InterceptedMetricsSvc>;
493
+ /// An [OperatorServiceClient] with the default interceptors attached.
494
+ pub type OperatorServiceClientWithMetrics = OperatorServiceClient<InterceptedMetricsSvc>;
495
+ /// An [TestServiceClient] with the default interceptors attached.
496
+ pub type TestServiceClientWithMetrics = TestServiceClient<InterceptedMetricsSvc>;
497
+ /// A [TemporalServiceClient] with the default interceptors attached.
498
+ pub type TemporalServiceClientWithMetrics = TemporalServiceClient<InterceptedMetricsSvc>;
499
+ type InterceptedMetricsSvc = InterceptedService<GrpcMetricSvc, ServiceCallInterceptor>;
500
+
501
+ /// Contains an instance of a namespace-bound client for interacting with the Temporal server
502
+ #[derive(Debug, Clone)]
503
+ pub struct Client {
504
+ /// Client for interacting with workflow service
505
+ inner: ConfiguredClient<TemporalServiceClientWithMetrics>,
506
+ /// The namespace this client interacts with
507
+ namespace: String,
508
+ /// If set, attach as the worker build id to relevant calls
509
+ bound_worker_build_id: Option<String>,
510
+ }
511
+
512
+ impl Client {
513
+ /// Create a new client from an existing configured lower level client and a namespace
514
+ pub fn new(
515
+ client: ConfiguredClient<TemporalServiceClientWithMetrics>,
516
+ namespace: String,
517
+ ) -> Self {
518
+ Client {
519
+ inner: client,
520
+ namespace,
521
+ bound_worker_build_id: None,
522
+ }
523
+ }
524
+
525
+ /// Return an auto-retrying version of the underling grpc client (instrumented with metrics
526
+ /// collection, if enabled).
527
+ ///
528
+ /// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
529
+ /// clones will keep re-using the same channel.
530
+ pub fn raw_retry_client(&self) -> RetryClient<WorkflowServiceClientWithMetrics> {
531
+ RetryClient::new(
532
+ self.raw_client().clone(),
533
+ self.inner.options.retry_config.clone(),
534
+ )
535
+ }
536
+
537
+ /// Access the underling grpc client. This raw client is not bound to a specific namespace.
538
+ ///
539
+ /// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
540
+ /// clones will keep re-using the same channel.
541
+ pub fn raw_client(&self) -> &WorkflowServiceClientWithMetrics {
542
+ self.inner.workflow_svc()
543
+ }
544
+
545
+ /// Return the options this client was initialized with
546
+ pub fn options(&self) -> &ClientOptions {
547
+ &self.inner.options
548
+ }
549
+
550
+ /// Return the options this client was initialized with mutably
551
+ pub fn options_mut(&mut self) -> &mut ClientOptions {
552
+ Arc::make_mut(&mut self.inner.options)
553
+ }
554
+
555
+ /// Set a worker build id to be attached to relevant requests. Unlikely to be useful outside
556
+ /// of core.
557
+ pub fn set_worker_build_id(&mut self, id: String) {
558
+ self.bound_worker_build_id = Some(id)
559
+ }
560
+
561
+ /// Returns a reference to the underlying client
562
+ pub fn inner(&self) -> &ConfiguredClient<TemporalServiceClientWithMetrics> {
563
+ &self.inner
564
+ }
565
+
566
+ /// Consumes self and returns the underlying client
567
+ pub fn into_inner(self) -> ConfiguredClient<TemporalServiceClientWithMetrics> {
568
+ self.inner
569
+ }
570
+
571
+ fn wf_svc(&self) -> WorkflowServiceClientWithMetrics {
572
+ self.inner.workflow_svc().clone()
573
+ }
574
+ }
575
+
576
+ /// Enum to help reference a namespace by either the namespace name or the namespace id
577
+ #[derive(Clone)]
578
+ pub enum Namespace {
579
+ /// Namespace name
580
+ Name(String),
581
+ /// Namespace id
582
+ Id(String),
583
+ }
584
+
585
+ impl Namespace {
586
+ fn into_describe_namespace_request(self) -> DescribeNamespaceRequest {
587
+ let (namespace, id) = match self {
588
+ Namespace::Name(n) => (n, "".to_owned()),
589
+ Namespace::Id(n) => ("".to_owned(), n),
590
+ };
591
+ DescribeNamespaceRequest { namespace, id }
592
+ }
593
+ }
594
+
595
+ /// This trait provides higher-level friendlier interaction with the server.
596
+ /// See the [WorkflowService] trait for a lower-level client.
597
+ #[cfg_attr(test, mockall::automock)]
598
+ #[async_trait::async_trait]
599
+ pub trait WorkflowClientTrait {
600
+ /// Starts workflow execution.
601
+ async fn start_workflow(
602
+ &self,
603
+ input: Vec<Payload>,
604
+ task_queue: String,
605
+ workflow_id: String,
606
+ workflow_type: String,
607
+ request_id: Option<String>,
608
+ options: WorkflowOptions,
609
+ ) -> Result<StartWorkflowExecutionResponse>;
610
+
611
+ /// Notifies the server that workflow tasks for a given workflow should be sent to the normal
612
+ /// non-sticky task queue. This normally happens when workflow has been evicted from the cache.
613
+ async fn reset_sticky_task_queue(
614
+ &self,
615
+ workflow_id: String,
616
+ run_id: String,
617
+ ) -> Result<ResetStickyTaskQueueResponse>;
618
+
619
+ /// Complete activity task by sending response to the server. `task_token` contains activity
620
+ /// identifier that would've been received from polling for an activity task. `result` is a blob
621
+ /// that contains activity response.
622
+ async fn complete_activity_task(
623
+ &self,
624
+ task_token: TaskToken,
625
+ result: Option<Payloads>,
626
+ ) -> Result<RespondActivityTaskCompletedResponse>;
627
+
628
+ /// Report activity task heartbeat by sending details to the server. `task_token` contains
629
+ /// activity identifier that would've been received from polling for an activity task. `result`
630
+ /// contains `cancel_requested` flag, which if set to true indicates that activity has been
631
+ /// cancelled.
632
+ async fn record_activity_heartbeat(
633
+ &self,
634
+ task_token: TaskToken,
635
+ details: Option<Payloads>,
636
+ ) -> Result<RecordActivityTaskHeartbeatResponse>;
637
+
638
+ /// Cancel activity task by sending response to the server. `task_token` contains activity
639
+ /// identifier that would've been received from polling for an activity task. `details` is a
640
+ /// blob that provides arbitrary user defined cancellation info.
641
+ async fn cancel_activity_task(
642
+ &self,
643
+ task_token: TaskToken,
644
+ details: Option<Payloads>,
645
+ ) -> Result<RespondActivityTaskCanceledResponse>;
646
+
647
+ /// Fail activity task by sending response to the server. `task_token` contains activity
648
+ /// identifier that would've been received from polling for an activity task. `failure` provides
649
+ /// failure details, such as message, cause and stack trace.
650
+ async fn fail_activity_task(
651
+ &self,
652
+ task_token: TaskToken,
653
+ failure: Option<Failure>,
654
+ ) -> Result<RespondActivityTaskFailedResponse>;
655
+
656
+ /// Fail task by sending the failure to the server. `task_token` is the task token that would've
657
+ /// been received from polling for a workflow activation.
658
+ async fn fail_workflow_task(
659
+ &self,
660
+ task_token: TaskToken,
661
+ cause: WorkflowTaskFailedCause,
662
+ failure: Option<Failure>,
663
+ ) -> Result<RespondWorkflowTaskFailedResponse>;
664
+
665
+ /// Send a signal to a certain workflow instance
666
+ async fn signal_workflow_execution(
667
+ &self,
668
+ workflow_id: String,
669
+ run_id: String,
670
+ signal_name: String,
671
+ payloads: Option<Payloads>,
672
+ request_id: Option<String>,
673
+ ) -> Result<SignalWorkflowExecutionResponse>;
674
+
675
+ /// Send signal and start workflow transcationally
676
+ //#TODO maybe lift the Signal type from sdk::workflow_context::options
677
+ #[allow(clippy::too_many_arguments)]
678
+ async fn signal_with_start_workflow_execution(
679
+ &self,
680
+ input: Option<Payloads>,
681
+ task_queue: String,
682
+ workflow_id: String,
683
+ workflow_type: String,
684
+ request_id: Option<String>,
685
+ options: WorkflowOptions,
686
+ signal_name: String,
687
+ signal_input: Option<Payloads>,
688
+ signal_header: Option<Header>,
689
+ ) -> Result<SignalWithStartWorkflowExecutionResponse>;
690
+
691
+ /// Request a query of a certain workflow instance
692
+ async fn query_workflow_execution(
693
+ &self,
694
+ workflow_id: String,
695
+ run_id: String,
696
+ query: WorkflowQuery,
697
+ ) -> Result<QueryWorkflowResponse>;
698
+
699
+ /// Get information about a workflow run
700
+ async fn describe_workflow_execution(
701
+ &self,
702
+ workflow_id: String,
703
+ run_id: Option<String>,
704
+ ) -> Result<DescribeWorkflowExecutionResponse>;
705
+
706
+ /// Get history for a particular workflow run
707
+ async fn get_workflow_execution_history(
708
+ &self,
709
+ workflow_id: String,
710
+ run_id: Option<String>,
711
+ page_token: Vec<u8>,
712
+ ) -> Result<GetWorkflowExecutionHistoryResponse>;
713
+
714
+ /// Respond to a legacy query-only workflow task
715
+ async fn respond_legacy_query(
716
+ &self,
717
+ task_token: TaskToken,
718
+ query_result: QueryResult,
719
+ ) -> Result<RespondQueryTaskCompletedResponse>;
720
+
721
+ /// Cancel a currently executing workflow
722
+ async fn cancel_workflow_execution(
723
+ &self,
724
+ workflow_id: String,
725
+ run_id: Option<String>,
726
+ reason: String,
727
+ request_id: Option<String>,
728
+ ) -> Result<RequestCancelWorkflowExecutionResponse>;
729
+
730
+ /// Terminate a currently executing workflow
731
+ async fn terminate_workflow_execution(
732
+ &self,
733
+ workflow_id: String,
734
+ run_id: Option<String>,
735
+ ) -> Result<TerminateWorkflowExecutionResponse>;
736
+
737
+ /// Lists all available namespaces
738
+ async fn list_namespaces(&self) -> Result<ListNamespacesResponse>;
739
+
740
+ /// Query namespace details
741
+ async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse>;
742
+
743
+ /// List open workflows with Standard Visibility filtering
744
+ async fn list_open_workflow_executions(
745
+ &self,
746
+ max_page_size: i32,
747
+ next_page_token: Vec<u8>,
748
+ start_time_filter: Option<StartTimeFilter>,
749
+ filters: Option<ListOpenFilters>,
750
+ ) -> Result<ListOpenWorkflowExecutionsResponse>;
751
+
752
+ /// List closed workflows Standard Visibility filtering
753
+ async fn list_closed_workflow_executions(
754
+ &self,
755
+ max_page_size: i32,
756
+ next_page_token: Vec<u8>,
757
+ start_time_filter: Option<StartTimeFilter>,
758
+ filters: Option<ListClosedFilters>,
759
+ ) -> Result<ListClosedWorkflowExecutionsResponse>;
760
+
761
+ /// List workflows with Advanced Visibility filtering
762
+ async fn list_workflow_executions(
763
+ &self,
764
+ max_page_size: i32,
765
+ next_page_token: Vec<u8>,
766
+ query: String,
767
+ ) -> Result<ListWorkflowExecutionsResponse>;
768
+
769
+ /// Returns options that were used to initialize the client
770
+ fn get_options(&self) -> &ClientOptions;
771
+
772
+ /// Returns the namespace this client is bound to
773
+ fn namespace(&self) -> &str;
774
+ }
775
+
776
+ /// Optional fields supplied at the start of workflow execution
777
+ #[derive(Debug, Clone, Default)]
778
+ pub struct WorkflowOptions {
779
+ /// Set the policy for reusing the workflow id
780
+ pub id_reuse_policy: WorkflowIdReusePolicy,
781
+
782
+ /// Optionally set the execution timeout for the workflow
783
+ /// <https://docs.temporal.io/workflows/#workflow-execution-timeout>
784
+ pub execution_timeout: Option<Duration>,
785
+
786
+ /// Optionally indicates the default run timeout for a workflow run
787
+ pub run_timeout: Option<Duration>,
788
+
789
+ /// Optionally indicates the default task timeout for a workflow run
790
+ pub task_timeout: Option<Duration>,
791
+
792
+ /// Optionally set a cron schedule for the workflow
793
+ pub cron_schedule: Option<String>,
794
+
795
+ /// Optionally associate extra search attributes with a workflow
796
+ pub search_attributes: Option<HashMap<String, Payload>>,
797
+ }
798
+
799
+ #[async_trait::async_trait]
800
+ impl WorkflowClientTrait for Client {
801
+ async fn start_workflow(
802
+ &self,
803
+ input: Vec<Payload>,
804
+ task_queue: String,
805
+ workflow_id: String,
806
+ workflow_type: String,
807
+ request_id: Option<String>,
808
+ options: WorkflowOptions,
809
+ ) -> Result<StartWorkflowExecutionResponse> {
810
+ Ok(self
811
+ .wf_svc()
812
+ .start_workflow_execution(StartWorkflowExecutionRequest {
813
+ namespace: self.namespace.clone(),
814
+ input: input.into_payloads(),
815
+ workflow_id,
816
+ workflow_type: Some(WorkflowType {
817
+ name: workflow_type,
818
+ }),
819
+ task_queue: Some(TaskQueue {
820
+ name: task_queue,
821
+ kind: TaskQueueKind::Unspecified as i32,
822
+ }),
823
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
824
+ workflow_id_reuse_policy: options.id_reuse_policy as i32,
825
+ workflow_execution_timeout: options
826
+ .execution_timeout
827
+ .and_then(|d| d.try_into().ok()),
828
+ workflow_run_timeout: options.execution_timeout.and_then(|d| d.try_into().ok()),
829
+ workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
830
+ search_attributes: options.search_attributes.and_then(|d| d.try_into().ok()),
831
+ cron_schedule: options.cron_schedule.unwrap_or_default(),
832
+ ..Default::default()
833
+ })
834
+ .await?
835
+ .into_inner())
836
+ }
837
+
838
+ async fn reset_sticky_task_queue(
839
+ &self,
840
+ workflow_id: String,
841
+ run_id: String,
842
+ ) -> Result<ResetStickyTaskQueueResponse> {
843
+ let request = ResetStickyTaskQueueRequest {
844
+ namespace: self.namespace.clone(),
845
+ execution: Some(WorkflowExecution {
846
+ workflow_id,
847
+ run_id,
848
+ }),
849
+ };
850
+ Ok(self
851
+ .wf_svc()
852
+ .reset_sticky_task_queue(request)
853
+ .await?
854
+ .into_inner())
855
+ }
856
+
857
+ async fn complete_activity_task(
858
+ &self,
859
+ task_token: TaskToken,
860
+ result: Option<Payloads>,
861
+ ) -> Result<RespondActivityTaskCompletedResponse> {
862
+ Ok(self
863
+ .wf_svc()
864
+ .respond_activity_task_completed(RespondActivityTaskCompletedRequest {
865
+ task_token: task_token.0,
866
+ result,
867
+ identity: self.inner.options.identity.clone(),
868
+ namespace: self.namespace.clone(),
869
+ })
870
+ .await?
871
+ .into_inner())
872
+ }
873
+
874
+ async fn record_activity_heartbeat(
875
+ &self,
876
+ task_token: TaskToken,
877
+ details: Option<Payloads>,
878
+ ) -> Result<RecordActivityTaskHeartbeatResponse> {
879
+ Ok(self
880
+ .wf_svc()
881
+ .record_activity_task_heartbeat(RecordActivityTaskHeartbeatRequest {
882
+ task_token: task_token.0,
883
+ details,
884
+ identity: self.inner.options.identity.clone(),
885
+ namespace: self.namespace.clone(),
886
+ })
887
+ .await?
888
+ .into_inner())
889
+ }
890
+
891
+ async fn cancel_activity_task(
892
+ &self,
893
+ task_token: TaskToken,
894
+ details: Option<Payloads>,
895
+ ) -> Result<RespondActivityTaskCanceledResponse> {
896
+ Ok(self
897
+ .wf_svc()
898
+ .respond_activity_task_canceled(RespondActivityTaskCanceledRequest {
899
+ task_token: task_token.0,
900
+ details,
901
+ identity: self.inner.options.identity.clone(),
902
+ namespace: self.namespace.clone(),
903
+ })
904
+ .await?
905
+ .into_inner())
906
+ }
907
+
908
+ async fn fail_activity_task(
909
+ &self,
910
+ task_token: TaskToken,
911
+ failure: Option<Failure>,
912
+ ) -> Result<RespondActivityTaskFailedResponse> {
913
+ Ok(self
914
+ .wf_svc()
915
+ .respond_activity_task_failed(RespondActivityTaskFailedRequest {
916
+ task_token: task_token.0,
917
+ failure,
918
+ identity: self.inner.options.identity.clone(),
919
+ namespace: self.namespace.clone(),
920
+ // TODO: Implement - https://github.com/temporalio/sdk-core/issues/293
921
+ last_heartbeat_details: None,
922
+ })
923
+ .await?
924
+ .into_inner())
925
+ }
926
+
927
+ async fn fail_workflow_task(
928
+ &self,
929
+ task_token: TaskToken,
930
+ cause: WorkflowTaskFailedCause,
931
+ failure: Option<Failure>,
932
+ ) -> Result<RespondWorkflowTaskFailedResponse> {
933
+ let request = RespondWorkflowTaskFailedRequest {
934
+ task_token: task_token.0,
935
+ cause: cause as i32,
936
+ failure,
937
+ identity: self.inner.options.identity.clone(),
938
+ binary_checksum: self.bound_worker_build_id.clone().unwrap_or_default(),
939
+ namespace: self.namespace.clone(),
940
+ };
941
+ Ok(self
942
+ .wf_svc()
943
+ .respond_workflow_task_failed(request)
944
+ .await?
945
+ .into_inner())
946
+ }
947
+
948
+ async fn signal_workflow_execution(
949
+ &self,
950
+ workflow_id: String,
951
+ run_id: String,
952
+ signal_name: String,
953
+ payloads: Option<Payloads>,
954
+ request_id: Option<String>,
955
+ ) -> Result<SignalWorkflowExecutionResponse> {
956
+ Ok(self
957
+ .wf_svc()
958
+ .signal_workflow_execution(SignalWorkflowExecutionRequest {
959
+ namespace: self.namespace.clone(),
960
+ workflow_execution: Some(WorkflowExecution {
961
+ workflow_id,
962
+ run_id,
963
+ }),
964
+ signal_name,
965
+ input: payloads,
966
+ identity: self.inner.options.identity.clone(),
967
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
968
+ ..Default::default()
969
+ })
970
+ .await?
971
+ .into_inner())
972
+ }
973
+
974
+ async fn signal_with_start_workflow_execution(
975
+ &self,
976
+ input: Option<Payloads>,
977
+ task_queue: String,
978
+ workflow_id: String,
979
+ workflow_type: String,
980
+ request_id: Option<String>,
981
+ options: WorkflowOptions,
982
+ signal_name: String,
983
+ signal_input: Option<Payloads>,
984
+ signal_header: Option<Header>,
985
+ ) -> Result<SignalWithStartWorkflowExecutionResponse> {
986
+ Ok(self
987
+ .wf_svc()
988
+ .signal_with_start_workflow_execution(SignalWithStartWorkflowExecutionRequest {
989
+ namespace: self.namespace.clone(),
990
+ workflow_id,
991
+ workflow_type: Some(WorkflowType {
992
+ name: workflow_type,
993
+ }),
994
+ task_queue: Some(TaskQueue {
995
+ name: task_queue,
996
+ kind: TaskQueueKind::Normal as i32,
997
+ }),
998
+ input,
999
+ signal_name,
1000
+ signal_input,
1001
+ identity: self.inner.options.identity.clone(),
1002
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1003
+ workflow_id_reuse_policy: options.id_reuse_policy as i32,
1004
+ workflow_execution_timeout: options
1005
+ .execution_timeout
1006
+ .and_then(|d| d.try_into().ok()),
1007
+ workflow_run_timeout: options.execution_timeout.and_then(|d| d.try_into().ok()),
1008
+ workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
1009
+ search_attributes: options.search_attributes.and_then(|d| d.try_into().ok()),
1010
+ cron_schedule: options.cron_schedule.unwrap_or_default(),
1011
+ header: signal_header,
1012
+ ..Default::default()
1013
+ })
1014
+ .await?
1015
+ .into_inner())
1016
+ }
1017
+
1018
+ async fn query_workflow_execution(
1019
+ &self,
1020
+ workflow_id: String,
1021
+ run_id: String,
1022
+ query: WorkflowQuery,
1023
+ ) -> Result<QueryWorkflowResponse> {
1024
+ Ok(self
1025
+ .wf_svc()
1026
+ .query_workflow(QueryWorkflowRequest {
1027
+ namespace: self.namespace.clone(),
1028
+ execution: Some(WorkflowExecution {
1029
+ workflow_id,
1030
+ run_id,
1031
+ }),
1032
+ query: Some(query),
1033
+ query_reject_condition: 1,
1034
+ })
1035
+ .await?
1036
+ .into_inner())
1037
+ }
1038
+
1039
+ async fn describe_workflow_execution(
1040
+ &self,
1041
+ workflow_id: String,
1042
+ run_id: Option<String>,
1043
+ ) -> Result<DescribeWorkflowExecutionResponse> {
1044
+ Ok(self
1045
+ .wf_svc()
1046
+ .describe_workflow_execution(DescribeWorkflowExecutionRequest {
1047
+ namespace: self.namespace.clone(),
1048
+ execution: Some(WorkflowExecution {
1049
+ workflow_id,
1050
+ run_id: run_id.unwrap_or_default(),
1051
+ }),
1052
+ })
1053
+ .await?
1054
+ .into_inner())
1055
+ }
1056
+
1057
+ async fn get_workflow_execution_history(
1058
+ &self,
1059
+ workflow_id: String,
1060
+ run_id: Option<String>,
1061
+ page_token: Vec<u8>,
1062
+ ) -> Result<GetWorkflowExecutionHistoryResponse> {
1063
+ Ok(self
1064
+ .wf_svc()
1065
+ .get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
1066
+ namespace: self.namespace.clone(),
1067
+ execution: Some(WorkflowExecution {
1068
+ workflow_id,
1069
+ run_id: run_id.unwrap_or_default(),
1070
+ }),
1071
+ next_page_token: page_token,
1072
+ ..Default::default()
1073
+ })
1074
+ .await?
1075
+ .into_inner())
1076
+ }
1077
+
1078
+ async fn respond_legacy_query(
1079
+ &self,
1080
+ task_token: TaskToken,
1081
+ query_result: QueryResult,
1082
+ ) -> Result<RespondQueryTaskCompletedResponse> {
1083
+ let (_, completed_type, query_result, error_message) = query_result.into_components();
1084
+ Ok(self
1085
+ .wf_svc()
1086
+ .respond_query_task_completed(RespondQueryTaskCompletedRequest {
1087
+ task_token: task_token.into(),
1088
+ completed_type: completed_type as i32,
1089
+ query_result,
1090
+ error_message,
1091
+ namespace: self.namespace.clone(),
1092
+ })
1093
+ .await?
1094
+ .into_inner())
1095
+ }
1096
+
1097
+ async fn cancel_workflow_execution(
1098
+ &self,
1099
+ workflow_id: String,
1100
+ run_id: Option<String>,
1101
+ reason: String,
1102
+ request_id: Option<String>,
1103
+ ) -> Result<RequestCancelWorkflowExecutionResponse> {
1104
+ Ok(self
1105
+ .wf_svc()
1106
+ .request_cancel_workflow_execution(RequestCancelWorkflowExecutionRequest {
1107
+ namespace: self.namespace.clone(),
1108
+ workflow_execution: Some(WorkflowExecution {
1109
+ workflow_id,
1110
+ run_id: run_id.unwrap_or_default(),
1111
+ }),
1112
+ identity: self.inner.options.identity.clone(),
1113
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1114
+ first_execution_run_id: "".to_string(),
1115
+ reason,
1116
+ })
1117
+ .await?
1118
+ .into_inner())
1119
+ }
1120
+
1121
+ async fn terminate_workflow_execution(
1122
+ &self,
1123
+ workflow_id: String,
1124
+ run_id: Option<String>,
1125
+ ) -> Result<TerminateWorkflowExecutionResponse> {
1126
+ Ok(self
1127
+ .wf_svc()
1128
+ .terminate_workflow_execution(TerminateWorkflowExecutionRequest {
1129
+ namespace: self.namespace.clone(),
1130
+ workflow_execution: Some(WorkflowExecution {
1131
+ workflow_id,
1132
+ run_id: run_id.unwrap_or_default(),
1133
+ }),
1134
+ reason: "".to_string(),
1135
+ details: None,
1136
+ identity: self.inner.options.identity.clone(),
1137
+ first_execution_run_id: "".to_string(),
1138
+ })
1139
+ .await?
1140
+ .into_inner())
1141
+ }
1142
+
1143
+ async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
1144
+ Ok(self
1145
+ .wf_svc()
1146
+ .list_namespaces(ListNamespacesRequest::default())
1147
+ .await?
1148
+ .into_inner())
1149
+ }
1150
+
1151
+ async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
1152
+ Ok(self
1153
+ .wf_svc()
1154
+ .describe_namespace(namespace.into_describe_namespace_request())
1155
+ .await?
1156
+ .into_inner())
1157
+ }
1158
+
1159
+ async fn list_open_workflow_executions(
1160
+ &self,
1161
+ maximum_page_size: i32,
1162
+ next_page_token: Vec<u8>,
1163
+ start_time_filter: Option<StartTimeFilter>,
1164
+ filters: Option<ListOpenFilters>,
1165
+ ) -> Result<ListOpenWorkflowExecutionsResponse> {
1166
+ Ok(self
1167
+ .wf_svc()
1168
+ .list_open_workflow_executions(ListOpenWorkflowExecutionsRequest {
1169
+ namespace: self.namespace.clone(),
1170
+ maximum_page_size,
1171
+ next_page_token,
1172
+ start_time_filter,
1173
+ filters,
1174
+ })
1175
+ .await?
1176
+ .into_inner())
1177
+ }
1178
+
1179
+ async fn list_closed_workflow_executions(
1180
+ &self,
1181
+ maximum_page_size: i32,
1182
+ next_page_token: Vec<u8>,
1183
+ start_time_filter: Option<StartTimeFilter>,
1184
+ filters: Option<ListClosedFilters>,
1185
+ ) -> Result<ListClosedWorkflowExecutionsResponse> {
1186
+ Ok(self
1187
+ .wf_svc()
1188
+ .list_closed_workflow_executions(ListClosedWorkflowExecutionsRequest {
1189
+ namespace: self.namespace.clone(),
1190
+ maximum_page_size,
1191
+ next_page_token,
1192
+ start_time_filter,
1193
+ filters,
1194
+ })
1195
+ .await?
1196
+ .into_inner())
1197
+ }
1198
+
1199
+ async fn list_workflow_executions(
1200
+ &self,
1201
+ page_size: i32,
1202
+ next_page_token: Vec<u8>,
1203
+ query: String,
1204
+ ) -> Result<ListWorkflowExecutionsResponse> {
1205
+ Ok(self
1206
+ .wf_svc()
1207
+ .list_workflow_executions(ListWorkflowExecutionsRequest {
1208
+ namespace: self.namespace.clone(),
1209
+ page_size,
1210
+ next_page_token,
1211
+ query,
1212
+ })
1213
+ .await?
1214
+ .into_inner())
1215
+ }
1216
+
1217
+ fn get_options(&self) -> &ClientOptions {
1218
+ &self.inner.options
1219
+ }
1220
+
1221
+ fn namespace(&self) -> &str {
1222
+ &self.namespace
1223
+ }
1224
+ }
1225
+
1226
+ mod sealed {
1227
+ use crate::{InterceptedMetricsSvc, RawClientLike, WorkflowClientTrait};
1228
+
1229
+ pub trait WfHandleClient:
1230
+ WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
1231
+ {
1232
+ }
1233
+ impl<T> WfHandleClient for T where
1234
+ T: WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
1235
+ {
1236
+ }
1237
+ }
1238
+
1239
+ /// Additional methods for workflow clients
1240
+ pub trait WfClientExt: WfHandleClient + Sized + Clone {
1241
+ /// Create an untyped handle for a workflow execution, which can be used to do things like
1242
+ /// wait for that workflow's result. `run_id` may be left blank to target the latest run.
1243
+ fn get_untyped_workflow_handle(
1244
+ &self,
1245
+ workflow_id: impl Into<String>,
1246
+ run_id: impl Into<String>,
1247
+ ) -> UntypedWorkflowHandle<Self> {
1248
+ let rid = run_id.into();
1249
+ UntypedWorkflowHandle::new(
1250
+ self.clone(),
1251
+ WorkflowExecutionInfo {
1252
+ namespace: self.namespace().to_string(),
1253
+ workflow_id: workflow_id.into(),
1254
+ run_id: if rid.is_empty() { None } else { Some(rid) },
1255
+ },
1256
+ )
1257
+ }
1258
+ }
1259
+ impl<T> WfClientExt for T where T: WfHandleClient + Clone + Sized {}
1260
+
1261
+ #[cfg(test)]
1262
+ mod tests {
1263
+ use super::*;
1264
+
1265
+ #[test]
1266
+ fn respects_per_call_headers() {
1267
+ let opts = ClientOptionsBuilder::default()
1268
+ .identity("enchicat".to_string())
1269
+ .target_url(Url::parse("https://smolkitty").unwrap())
1270
+ .client_name("cute-kitty".to_string())
1271
+ .client_version("0.1.0".to_string())
1272
+ .build()
1273
+ .unwrap();
1274
+
1275
+ let mut static_headers = HashMap::new();
1276
+ static_headers.insert("enchi".to_string(), "kitty".to_string());
1277
+ let mut iceptor = ServiceCallInterceptor {
1278
+ opts,
1279
+ headers: Arc::new(RwLock::new(static_headers)),
1280
+ };
1281
+ let mut req = tonic::Request::new(());
1282
+ req.metadata_mut().insert("enchi", "cat".parse().unwrap());
1283
+ let next_req = iceptor.call(req).unwrap();
1284
+ assert_eq!(next_req.metadata().get("enchi").unwrap(), "cat");
1285
+ }
1286
+ }