temporalio 0.0.0 → 0.0.1

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