temporalio 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +20 -0
  4. data/README.md +130 -0
  5. data/bridge/Cargo.lock +2865 -0
  6. data/bridge/Cargo.toml +26 -0
  7. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  8. data/bridge/sdk-core/Cargo.lock +2606 -0
  9. data/bridge/sdk-core/Cargo.toml +2 -0
  10. data/bridge/sdk-core/LICENSE.txt +23 -0
  11. data/bridge/sdk-core/README.md +107 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  13. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  14. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  15. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  16. data/bridge/sdk-core/bridge-ffi/Cargo.toml +24 -0
  17. data/bridge/sdk-core/bridge-ffi/LICENSE.txt +23 -0
  18. data/bridge/sdk-core/bridge-ffi/build.rs +25 -0
  19. data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +249 -0
  20. data/bridge/sdk-core/bridge-ffi/src/lib.rs +825 -0
  21. data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +211 -0
  22. data/bridge/sdk-core/client/Cargo.toml +40 -0
  23. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  24. data/bridge/sdk-core/client/src/lib.rs +1294 -0
  25. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  26. data/bridge/sdk-core/client/src/raw.rs +931 -0
  27. data/bridge/sdk-core/client/src/retry.rs +674 -0
  28. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  29. data/bridge/sdk-core/core/Cargo.toml +116 -0
  30. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  31. data/bridge/sdk-core/core/benches/workflow_replay.rs +73 -0
  32. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  33. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +911 -0
  34. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  35. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  36. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +515 -0
  37. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  38. data/bridge/sdk-core/core/src/core_tests/queries.rs +736 -0
  39. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  40. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  41. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  42. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2070 -0
  43. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  44. data/bridge/sdk-core/core/src/lib.rs +175 -0
  45. data/bridge/sdk-core/core/src/log_export.rs +62 -0
  46. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  47. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  48. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  49. data/bridge/sdk-core/core/src/replay/mod.rs +71 -0
  50. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  51. data/bridge/sdk-core/core/src/telemetry/metrics.rs +383 -0
  52. data/bridge/sdk-core/core/src/telemetry/mod.rs +412 -0
  53. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +77 -0
  54. data/bridge/sdk-core/core/src/test_help/mod.rs +875 -0
  55. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  56. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1042 -0
  57. data/bridge/sdk-core/core/src/worker/activities.rs +464 -0
  58. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  59. data/bridge/sdk-core/core/src/worker/client.rs +347 -0
  60. data/bridge/sdk-core/core/src/worker/mod.rs +566 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +110 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +458 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +911 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +298 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +171 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +860 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +140 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +161 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +133 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1448 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +342 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +127 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +712 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +71 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +443 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +439 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +169 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +246 -0
  80. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  81. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1184 -0
  82. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +277 -0
  83. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  84. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +647 -0
  85. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1143 -0
  86. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  87. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  88. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +940 -0
  89. data/bridge/sdk-core/core-api/Cargo.toml +31 -0
  90. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  91. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  92. data/bridge/sdk-core/core-api/src/lib.rs +151 -0
  93. data/bridge/sdk-core/core-api/src/worker.rs +135 -0
  94. data/bridge/sdk-core/etc/deps.svg +187 -0
  95. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  96. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  97. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  98. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  99. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  100. data/bridge/sdk-core/fsm/README.md +3 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  115. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  116. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  117. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  118. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  119. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  120. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  121. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  122. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  123. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  124. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  125. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  126. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  127. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  128. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  129. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  130. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  131. data/bridge/sdk-core/protos/api_upstream/buf.yaml +12 -0
  132. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +259 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +55 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +168 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +97 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +751 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +161 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +99 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +145 -0
  164. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1124 -0
  165. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +401 -0
  166. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +210 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  174. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +261 -0
  175. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +297 -0
  176. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  179. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  180. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  181. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  182. data/bridge/sdk-core/rustfmt.toml +1 -0
  183. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  184. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  185. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  186. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  187. data/bridge/sdk-core/sdk/src/conversions.rs +8 -0
  188. data/bridge/sdk-core/sdk/src/interceptors.rs +17 -0
  189. data/bridge/sdk-core/sdk/src/lib.rs +792 -0
  190. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  191. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  192. data/bridge/sdk-core/sdk/src/workflow_context.rs +683 -0
  193. data/bridge/sdk-core/sdk/src/workflow_future.rs +503 -0
  194. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  195. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  196. data/bridge/sdk-core/sdk-core-protos/build.rs +108 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +497 -0
  199. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  200. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1910 -0
  201. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  202. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  203. data/bridge/sdk-core/test-utils/Cargo.toml +35 -0
  204. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  205. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  206. data/bridge/sdk-core/test-utils/src/lib.rs +598 -0
  207. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  208. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  209. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +218 -0
  210. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +146 -0
  211. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  212. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +634 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +137 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  227. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  228. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +587 -0
  229. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  230. data/bridge/sdk-core/tests/main.rs +111 -0
  231. data/bridge/sdk-core/tests/runner.rs +93 -0
  232. data/bridge/src/connection.rs +167 -0
  233. data/bridge/src/lib.rs +180 -0
  234. data/bridge/src/runtime.rs +47 -0
  235. data/bridge/src/worker.rs +73 -0
  236. data/ext/Rakefile +9 -0
  237. data/lib/bridge.so +0 -0
  238. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  239. data/lib/gen/temporal/api/batch/v1/message_pb.rb +48 -0
  240. data/lib/gen/temporal/api/cluster/v1/message_pb.rb +67 -0
  241. data/lib/gen/temporal/api/command/v1/message_pb.rb +166 -0
  242. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  243. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +32 -0
  244. data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +26 -0
  245. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +37 -0
  246. data/lib/gen/temporal/api/enums/v1/common_pb.rb +41 -0
  247. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +67 -0
  248. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +71 -0
  249. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  250. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  251. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  252. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  253. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  254. data/lib/gen/temporal/api/enums/v1/update_pb.rb +28 -0
  255. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  256. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  257. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  258. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  259. data/lib/gen/temporal/api/history/v1/message_pb.rb +489 -0
  260. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  261. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +125 -0
  262. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  263. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  264. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  265. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +128 -0
  266. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  267. data/lib/gen/temporal/api/update/v1/message_pb.rb +26 -0
  268. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  269. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +110 -0
  270. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +771 -0
  271. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  272. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  273. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  274. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  275. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  276. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  277. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  278. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  279. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +164 -0
  280. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +192 -0
  281. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  282. data/lib/temporal/bridge.rb +14 -0
  283. data/lib/temporal/client/implementation.rb +339 -0
  284. data/lib/temporal/client/workflow_handle.rb +243 -0
  285. data/lib/temporal/client.rb +144 -0
  286. data/lib/temporal/connection.rb +736 -0
  287. data/lib/temporal/data_converter.rb +150 -0
  288. data/lib/temporal/error/failure.rb +194 -0
  289. data/lib/temporal/error/workflow_failure.rb +17 -0
  290. data/lib/temporal/errors.rb +22 -0
  291. data/lib/temporal/failure_converter/base.rb +26 -0
  292. data/lib/temporal/failure_converter/basic.rb +313 -0
  293. data/lib/temporal/failure_converter.rb +8 -0
  294. data/lib/temporal/interceptor/chain.rb +27 -0
  295. data/lib/temporal/interceptor/client.rb +102 -0
  296. data/lib/temporal/payload_codec/base.rb +32 -0
  297. data/lib/temporal/payload_converter/base.rb +24 -0
  298. data/lib/temporal/payload_converter/bytes.rb +26 -0
  299. data/lib/temporal/payload_converter/composite.rb +47 -0
  300. data/lib/temporal/payload_converter/encoding_base.rb +35 -0
  301. data/lib/temporal/payload_converter/json.rb +25 -0
  302. data/lib/temporal/payload_converter/nil.rb +25 -0
  303. data/lib/temporal/payload_converter.rb +14 -0
  304. data/lib/temporal/retry_policy.rb +82 -0
  305. data/lib/temporal/retry_state.rb +35 -0
  306. data/lib/temporal/runtime.rb +22 -0
  307. data/lib/temporal/timeout_type.rb +29 -0
  308. data/lib/temporal/version.rb +3 -0
  309. data/lib/temporal/workflow/execution_info.rb +54 -0
  310. data/lib/temporal/workflow/execution_status.rb +36 -0
  311. data/lib/temporal/workflow/id_reuse_policy.rb +36 -0
  312. data/lib/temporal/workflow/query_reject_condition.rb +33 -0
  313. data/lib/temporal.rb +8 -0
  314. data/lib/temporalio.rb +3 -0
  315. data/lib/thermite_patch.rb +23 -0
  316. data/temporalio.gemspec +41 -0
  317. metadata +583 -0
@@ -0,0 +1,674 @@
1
+ use crate::{
2
+ ClientOptions, ListClosedFilters, ListOpenFilters, Namespace, Result, RetryConfig,
3
+ StartTimeFilter, WorkflowClientTrait, WorkflowOptions,
4
+ };
5
+ use backoff::{backoff::Backoff, exponential::ExponentialBackoff, Clock, SystemClock};
6
+ use futures_retry::{ErrorHandler, FutureRetry, RetryPolicy};
7
+ use std::{fmt::Debug, future::Future, sync::Arc, time::Duration};
8
+ use temporal_sdk_core_protos::{
9
+ coresdk::workflow_commands::QueryResult,
10
+ temporal::api::{
11
+ common::v1::{Header, Payload, Payloads},
12
+ enums::v1::WorkflowTaskFailedCause,
13
+ failure::v1::Failure,
14
+ query::v1::WorkflowQuery,
15
+ workflowservice::v1::*,
16
+ },
17
+ TaskToken,
18
+ };
19
+ use tonic::Code;
20
+
21
+ /// List of gRPC error codes that client will retry.
22
+ pub const RETRYABLE_ERROR_CODES: [Code; 7] = [
23
+ Code::DataLoss,
24
+ Code::Internal,
25
+ Code::Unknown,
26
+ Code::ResourceExhausted,
27
+ Code::Aborted,
28
+ Code::OutOfRange,
29
+ Code::Unavailable,
30
+ ];
31
+ const LONG_POLL_FATAL_GRACE: Duration = Duration::from_secs(60);
32
+ /// Must match the method name in [crate::raw::WorkflowService]
33
+ const POLL_WORKFLOW_METH_NAME: &str = "poll_workflow_task_queue";
34
+ /// Must match the method name in [crate::raw::WorkflowService]
35
+ const POLL_ACTIVITY_METH_NAME: &str = "poll_activity_task_queue";
36
+
37
+ /// A wrapper for a [WorkflowClientTrait] or [crate::WorkflowService] implementor which performs
38
+ /// auto-retries
39
+ #[derive(Debug, Clone)]
40
+ pub struct RetryClient<SG> {
41
+ client: SG,
42
+ retry_config: Arc<RetryConfig>,
43
+ }
44
+
45
+ impl<SG> RetryClient<SG> {
46
+ /// Use the provided retry config with the provided client
47
+ pub fn new(client: SG, retry_config: RetryConfig) -> Self {
48
+ Self {
49
+ client,
50
+ retry_config: Arc::new(retry_config),
51
+ }
52
+ }
53
+ }
54
+
55
+ impl<SG> RetryClient<SG> {
56
+ /// Return the inner client type
57
+ pub fn get_client(&self) -> &SG {
58
+ &self.client
59
+ }
60
+
61
+ /// Return the inner client type mutably
62
+ pub fn get_client_mut(&mut self) -> &mut SG {
63
+ &mut self.client
64
+ }
65
+
66
+ /// Disable retry and return the inner client type
67
+ pub fn into_inner(self) -> SG {
68
+ self.client
69
+ }
70
+
71
+ /// Wraps a call to the underlying client with retry capability.
72
+ ///
73
+ /// This is the "old" path used by higher-level [WorkflowClientTrait] implementors
74
+ pub(crate) async fn call_with_retry<R, F, Fut>(
75
+ &self,
76
+ factory: F,
77
+ call_name: &'static str,
78
+ ) -> Result<R>
79
+ where
80
+ F: Fn() -> Fut + Unpin,
81
+ Fut: Future<Output = Result<R>>,
82
+ {
83
+ let rtc = self.get_retry_config(call_name);
84
+ let res = Self::make_future_retry(rtc, factory, call_name).await;
85
+ Ok(res.map_err(|(e, _attempt)| e)?.0)
86
+ }
87
+
88
+ pub(crate) fn get_retry_config(&self, call_name: &'static str) -> RetryConfig {
89
+ match CallType::from_call_name(call_name) {
90
+ CallType::Normal => (*self.retry_config).clone(),
91
+ CallType::LongPoll => RetryConfig::poll_retry_policy(),
92
+ }
93
+ }
94
+
95
+ pub(crate) fn make_future_retry<R, F, Fut>(
96
+ rtc: RetryConfig,
97
+ factory: F,
98
+ call_name: &'static str,
99
+ ) -> FutureRetry<F, TonicErrorHandler<SystemClock>>
100
+ where
101
+ F: FnMut() -> Fut + Unpin,
102
+ Fut: Future<Output = Result<R>>,
103
+ {
104
+ FutureRetry::new(factory, TonicErrorHandler::new(rtc, call_name))
105
+ }
106
+ }
107
+
108
+ #[derive(Debug)]
109
+ pub(crate) struct TonicErrorHandler<C: Clock> {
110
+ backoff: ExponentialBackoff<C>,
111
+ max_retries: usize,
112
+ call_type: CallType,
113
+ call_name: &'static str,
114
+ }
115
+ impl TonicErrorHandler<SystemClock> {
116
+ fn new(cfg: RetryConfig, call_name: &'static str) -> Self {
117
+ Self::new_with_clock(cfg, call_name, SystemClock::default())
118
+ }
119
+ }
120
+ impl<C> TonicErrorHandler<C>
121
+ where
122
+ C: Clock,
123
+ {
124
+ fn new_with_clock(cfg: RetryConfig, call_name: &'static str, clock: C) -> Self {
125
+ Self {
126
+ max_retries: cfg.max_retries,
127
+ call_type: CallType::from_call_name(call_name),
128
+ call_name,
129
+ backoff: cfg.into_exp_backoff(clock),
130
+ }
131
+ }
132
+ const fn should_log_retry_warning(&self, cur_attempt: usize) -> bool {
133
+ // Warn on more than 5 retries for unlimited retrying
134
+ if self.max_retries == 0 && cur_attempt > 5 {
135
+ return true;
136
+ }
137
+ // Warn if the attempts are more than 50% of max retries
138
+ if self.max_retries > 0 && cur_attempt * 2 >= self.max_retries {
139
+ return true;
140
+ }
141
+ false
142
+ }
143
+ }
144
+ #[doc(hidden)]
145
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
146
+ pub enum CallType {
147
+ Normal,
148
+ LongPoll,
149
+ }
150
+ impl CallType {
151
+ fn from_call_name(call_name: &str) -> Self {
152
+ match call_name {
153
+ POLL_WORKFLOW_METH_NAME | POLL_ACTIVITY_METH_NAME => CallType::LongPoll,
154
+ _ => CallType::Normal,
155
+ }
156
+ }
157
+ }
158
+
159
+ impl<C> ErrorHandler<tonic::Status> for TonicErrorHandler<C>
160
+ where
161
+ C: Clock,
162
+ {
163
+ type OutError = tonic::Status;
164
+
165
+ fn handle(&mut self, current_attempt: usize, e: tonic::Status) -> RetryPolicy<tonic::Status> {
166
+ // 0 max retries means unlimited retries
167
+ if self.max_retries > 0 && current_attempt >= self.max_retries {
168
+ return RetryPolicy::ForwardError(e);
169
+ }
170
+
171
+ let is_long_poll = self.call_type == CallType::LongPoll;
172
+ // Long polls are OK with being cancelled or running into the timeout because there's
173
+ // nothing to do but retry anyway
174
+ let long_poll_allowed =
175
+ is_long_poll && [Code::Cancelled, Code::DeadlineExceeded].contains(&e.code());
176
+
177
+ if RETRYABLE_ERROR_CODES.contains(&e.code()) || long_poll_allowed {
178
+ if current_attempt == 1 {
179
+ debug!(error=?e, "gRPC call {} failed on first attempt", self.call_name);
180
+ } else if self.should_log_retry_warning(current_attempt) {
181
+ warn!(error=?e, "gRPC call {} retried {} times", self.call_name, current_attempt);
182
+ }
183
+
184
+ match self.backoff.next_backoff() {
185
+ None => RetryPolicy::ForwardError(e), // None is returned when we've ran out of time
186
+ Some(backoff) => {
187
+ if cfg!(test) {
188
+ // Allow unit tests to do lots of retries quickly. This does *not* apply
189
+ // during integration testing, importantly.
190
+ RetryPolicy::WaitRetry(Duration::from_millis(1))
191
+ } else {
192
+ RetryPolicy::WaitRetry(backoff)
193
+ }
194
+ }
195
+ }
196
+ } else if is_long_poll && self.backoff.get_elapsed_time() <= LONG_POLL_FATAL_GRACE {
197
+ // We permit "fatal" errors while long polling for a while, because some proxies return
198
+ // stupid error codes while getting ready, among other weird infra issues
199
+ RetryPolicy::WaitRetry(self.backoff.max_interval)
200
+ } else {
201
+ RetryPolicy::ForwardError(e)
202
+ }
203
+ }
204
+ }
205
+
206
+ macro_rules! retry_call {
207
+ ($myself:ident, $call_name:ident) => { retry_call!($myself, $call_name,) };
208
+ ($myself:ident, $call_name:ident, $($args:expr),*) => {{
209
+ let call_name_str = stringify!($call_name);
210
+ let fact = || { $myself.get_client().$call_name($($args,)*)};
211
+ $myself.call_with_retry(fact, call_name_str).await
212
+ }}
213
+ }
214
+
215
+ // Ideally, this would be auto-implemented for anything that implements the raw client, but that
216
+ // breaks all our retry clients which use a mock since it's based on this trait currently. Ideally
217
+ // we would create an automock for the WorkflowServiceClient copy-paste trait and use that, but
218
+ // that's a huge pain. Maybe one day tonic will provide traits.
219
+ #[async_trait::async_trait]
220
+ impl<SG> WorkflowClientTrait for RetryClient<SG>
221
+ where
222
+ SG: WorkflowClientTrait + Send + Sync + 'static,
223
+ {
224
+ async fn start_workflow(
225
+ &self,
226
+ input: Vec<Payload>,
227
+ task_queue: String,
228
+ workflow_id: String,
229
+ workflow_type: String,
230
+ request_id: Option<String>,
231
+ options: WorkflowOptions,
232
+ ) -> Result<StartWorkflowExecutionResponse> {
233
+ retry_call!(
234
+ self,
235
+ start_workflow,
236
+ input.clone(),
237
+ task_queue.clone(),
238
+ workflow_id.clone(),
239
+ workflow_type.clone(),
240
+ request_id.clone(),
241
+ options.clone()
242
+ )
243
+ }
244
+
245
+ async fn reset_sticky_task_queue(
246
+ &self,
247
+ workflow_id: String,
248
+ run_id: String,
249
+ ) -> Result<ResetStickyTaskQueueResponse> {
250
+ retry_call!(
251
+ self,
252
+ reset_sticky_task_queue,
253
+ workflow_id.clone(),
254
+ run_id.clone()
255
+ )
256
+ }
257
+
258
+ async fn complete_activity_task(
259
+ &self,
260
+ task_token: TaskToken,
261
+ result: Option<Payloads>,
262
+ ) -> Result<RespondActivityTaskCompletedResponse> {
263
+ retry_call!(
264
+ self,
265
+ complete_activity_task,
266
+ task_token.clone(),
267
+ result.clone()
268
+ )
269
+ }
270
+
271
+ async fn record_activity_heartbeat(
272
+ &self,
273
+ task_token: TaskToken,
274
+ details: Option<Payloads>,
275
+ ) -> Result<RecordActivityTaskHeartbeatResponse> {
276
+ retry_call!(
277
+ self,
278
+ record_activity_heartbeat,
279
+ task_token.clone(),
280
+ details.clone()
281
+ )
282
+ }
283
+
284
+ async fn cancel_activity_task(
285
+ &self,
286
+ task_token: TaskToken,
287
+ details: Option<Payloads>,
288
+ ) -> Result<RespondActivityTaskCanceledResponse> {
289
+ retry_call!(
290
+ self,
291
+ cancel_activity_task,
292
+ task_token.clone(),
293
+ details.clone()
294
+ )
295
+ }
296
+
297
+ async fn fail_activity_task(
298
+ &self,
299
+ task_token: TaskToken,
300
+ failure: Option<Failure>,
301
+ ) -> Result<RespondActivityTaskFailedResponse> {
302
+ retry_call!(
303
+ self,
304
+ fail_activity_task,
305
+ task_token.clone(),
306
+ failure.clone()
307
+ )
308
+ }
309
+
310
+ async fn fail_workflow_task(
311
+ &self,
312
+ task_token: TaskToken,
313
+ cause: WorkflowTaskFailedCause,
314
+ failure: Option<Failure>,
315
+ ) -> Result<RespondWorkflowTaskFailedResponse> {
316
+ retry_call!(
317
+ self,
318
+ fail_workflow_task,
319
+ task_token.clone(),
320
+ cause,
321
+ failure.clone()
322
+ )
323
+ }
324
+
325
+ async fn signal_workflow_execution(
326
+ &self,
327
+ workflow_id: String,
328
+ run_id: String,
329
+ signal_name: String,
330
+ payloads: Option<Payloads>,
331
+ request_id: Option<String>,
332
+ ) -> Result<SignalWorkflowExecutionResponse> {
333
+ retry_call!(
334
+ self,
335
+ signal_workflow_execution,
336
+ workflow_id.clone(),
337
+ run_id.clone(),
338
+ signal_name.clone(),
339
+ payloads.clone(),
340
+ request_id.clone()
341
+ )
342
+ }
343
+
344
+ async fn signal_with_start_workflow_execution(
345
+ &self,
346
+ input: Option<Payloads>,
347
+ task_queue: String,
348
+ workflow_id: String,
349
+ workflow_type: String,
350
+ request_id: Option<String>,
351
+ options: WorkflowOptions,
352
+ signal_name: String,
353
+ signal_input: Option<Payloads>,
354
+ signal_header: Option<Header>,
355
+ ) -> Result<SignalWithStartWorkflowExecutionResponse> {
356
+ retry_call!(
357
+ self,
358
+ signal_with_start_workflow_execution,
359
+ input.clone(),
360
+ task_queue.clone(),
361
+ workflow_id.clone(),
362
+ workflow_type.clone(),
363
+ request_id.clone(),
364
+ options.clone(),
365
+ signal_name.clone(),
366
+ signal_input.clone(),
367
+ signal_header.clone()
368
+ )
369
+ }
370
+
371
+ async fn query_workflow_execution(
372
+ &self,
373
+ workflow_id: String,
374
+ run_id: String,
375
+ query: WorkflowQuery,
376
+ ) -> Result<QueryWorkflowResponse> {
377
+ retry_call!(
378
+ self,
379
+ query_workflow_execution,
380
+ workflow_id.clone(),
381
+ run_id.clone(),
382
+ query.clone()
383
+ )
384
+ }
385
+
386
+ async fn describe_workflow_execution(
387
+ &self,
388
+ workflow_id: String,
389
+ run_id: Option<String>,
390
+ ) -> Result<DescribeWorkflowExecutionResponse> {
391
+ retry_call!(
392
+ self,
393
+ describe_workflow_execution,
394
+ workflow_id.clone(),
395
+ run_id.clone()
396
+ )
397
+ }
398
+
399
+ async fn get_workflow_execution_history(
400
+ &self,
401
+ workflow_id: String,
402
+ run_id: Option<String>,
403
+ page_token: Vec<u8>,
404
+ ) -> Result<GetWorkflowExecutionHistoryResponse> {
405
+ retry_call!(
406
+ self,
407
+ get_workflow_execution_history,
408
+ workflow_id.clone(),
409
+ run_id.clone(),
410
+ page_token.clone()
411
+ )
412
+ }
413
+
414
+ async fn respond_legacy_query(
415
+ &self,
416
+ task_token: TaskToken,
417
+ query_result: QueryResult,
418
+ ) -> Result<RespondQueryTaskCompletedResponse> {
419
+ retry_call!(
420
+ self,
421
+ respond_legacy_query,
422
+ task_token.clone(),
423
+ query_result.clone()
424
+ )
425
+ }
426
+
427
+ async fn cancel_workflow_execution(
428
+ &self,
429
+ workflow_id: String,
430
+ run_id: Option<String>,
431
+ reason: String,
432
+ request_id: Option<String>,
433
+ ) -> Result<RequestCancelWorkflowExecutionResponse> {
434
+ retry_call!(
435
+ self,
436
+ cancel_workflow_execution,
437
+ workflow_id.clone(),
438
+ run_id.clone(),
439
+ reason.clone(),
440
+ request_id.clone()
441
+ )
442
+ }
443
+
444
+ async fn terminate_workflow_execution(
445
+ &self,
446
+ workflow_id: String,
447
+ run_id: Option<String>,
448
+ ) -> Result<TerminateWorkflowExecutionResponse> {
449
+ retry_call!(
450
+ self,
451
+ terminate_workflow_execution,
452
+ workflow_id.clone(),
453
+ run_id.clone()
454
+ )
455
+ }
456
+
457
+ async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
458
+ retry_call!(self, list_namespaces,)
459
+ }
460
+
461
+ async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
462
+ retry_call!(self, describe_namespace, namespace.clone())
463
+ }
464
+
465
+ async fn list_open_workflow_executions(
466
+ &self,
467
+ maximum_page_size: i32,
468
+ next_page_token: Vec<u8>,
469
+ start_time_filter: Option<StartTimeFilter>,
470
+ filters: Option<ListOpenFilters>,
471
+ ) -> Result<ListOpenWorkflowExecutionsResponse> {
472
+ retry_call!(
473
+ self,
474
+ list_open_workflow_executions,
475
+ maximum_page_size,
476
+ next_page_token.clone(),
477
+ start_time_filter.clone(),
478
+ filters.clone()
479
+ )
480
+ }
481
+
482
+ async fn list_closed_workflow_executions(
483
+ &self,
484
+ maximum_page_size: i32,
485
+ next_page_token: Vec<u8>,
486
+ start_time_filter: Option<StartTimeFilter>,
487
+ filters: Option<ListClosedFilters>,
488
+ ) -> Result<ListClosedWorkflowExecutionsResponse> {
489
+ retry_call!(
490
+ self,
491
+ list_closed_workflow_executions,
492
+ maximum_page_size,
493
+ next_page_token.clone(),
494
+ start_time_filter.clone(),
495
+ filters.clone()
496
+ )
497
+ }
498
+
499
+ async fn list_workflow_executions(
500
+ &self,
501
+ page_size: i32,
502
+ next_page_token: Vec<u8>,
503
+ query: String,
504
+ ) -> Result<ListWorkflowExecutionsResponse> {
505
+ retry_call!(
506
+ self,
507
+ list_workflow_executions,
508
+ page_size,
509
+ next_page_token.clone(),
510
+ query.clone()
511
+ )
512
+ }
513
+
514
+ fn get_options(&self) -> &ClientOptions {
515
+ self.client.get_options()
516
+ }
517
+
518
+ fn namespace(&self) -> &str {
519
+ self.client.namespace()
520
+ }
521
+ }
522
+
523
+ #[cfg(test)]
524
+ mod tests {
525
+ use super::*;
526
+ use crate::MockWorkflowClientTrait;
527
+ use assert_matches::assert_matches;
528
+ use backoff::Clock;
529
+ use std::{ops::Add, time::Instant};
530
+ use tonic::Status;
531
+
532
+ #[tokio::test]
533
+ async fn non_retryable_errors() {
534
+ for code in [
535
+ Code::InvalidArgument,
536
+ Code::NotFound,
537
+ Code::AlreadyExists,
538
+ Code::PermissionDenied,
539
+ Code::FailedPrecondition,
540
+ Code::Cancelled,
541
+ Code::DeadlineExceeded,
542
+ Code::Unauthenticated,
543
+ Code::Unimplemented,
544
+ ] {
545
+ let mut mock_client = MockWorkflowClientTrait::new();
546
+ mock_client
547
+ .expect_cancel_activity_task()
548
+ .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
549
+ .times(1);
550
+ let retry_client = RetryClient::new(mock_client, Default::default());
551
+ let result = retry_client
552
+ .cancel_activity_task(vec![1].into(), None)
553
+ .await;
554
+ // Expecting an error after a single attempt, since there was a non-retryable error.
555
+ assert!(result.is_err());
556
+ }
557
+ }
558
+
559
+ struct FixedClock(Instant);
560
+ impl Clock for FixedClock {
561
+ fn now(&self) -> Instant {
562
+ self.0
563
+ }
564
+ }
565
+
566
+ #[tokio::test]
567
+ async fn long_poll_non_retryable_errors() {
568
+ for code in [
569
+ Code::InvalidArgument,
570
+ Code::NotFound,
571
+ Code::AlreadyExists,
572
+ Code::PermissionDenied,
573
+ Code::FailedPrecondition,
574
+ Code::Unauthenticated,
575
+ Code::Unimplemented,
576
+ ] {
577
+ for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
578
+ let retry_cfg = RetryConfig::poll_retry_policy();
579
+ let mut err_handler = TonicErrorHandler {
580
+ max_retries: retry_cfg.max_retries,
581
+ call_type: CallType::LongPoll,
582
+ call_name,
583
+ backoff: retry_cfg.into_exp_backoff(FixedClock(Instant::now())),
584
+ };
585
+ let result = err_handler.handle(1, Status::new(code, "Ahh"));
586
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
587
+ err_handler.backoff.clock.0 = err_handler
588
+ .backoff
589
+ .clock
590
+ .0
591
+ .add(LONG_POLL_FATAL_GRACE + Duration::from_secs(1));
592
+ let result = err_handler.handle(2, Status::new(code, "Ahh"));
593
+ assert_matches!(result, RetryPolicy::ForwardError(_));
594
+ }
595
+ }
596
+ }
597
+
598
+ #[tokio::test]
599
+ async fn long_poll_retryable_errors_never_fatal() {
600
+ for code in RETRYABLE_ERROR_CODES {
601
+ for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
602
+ let retry_cfg = RetryConfig::poll_retry_policy();
603
+ let mut err_handler = TonicErrorHandler {
604
+ max_retries: retry_cfg.max_retries,
605
+ call_type: CallType::LongPoll,
606
+ call_name,
607
+ backoff: retry_cfg.into_exp_backoff(FixedClock(Instant::now())),
608
+ };
609
+ let result = err_handler.handle(1, Status::new(code, "Ahh"));
610
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
611
+ err_handler.backoff.clock.0 = err_handler
612
+ .backoff
613
+ .clock
614
+ .0
615
+ .add(LONG_POLL_FATAL_GRACE + Duration::from_secs(1));
616
+ let result = err_handler.handle(2, Status::new(code, "Ahh"));
617
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
618
+ }
619
+ }
620
+ }
621
+
622
+ #[tokio::test]
623
+ async fn retryable_errors() {
624
+ for code in RETRYABLE_ERROR_CODES {
625
+ let mut mock_client = MockWorkflowClientTrait::new();
626
+ mock_client
627
+ .expect_cancel_activity_task()
628
+ .returning(move |_, _| Err(Status::new(code, "retryable failure")))
629
+ .times(3);
630
+ mock_client
631
+ .expect_cancel_activity_task()
632
+ .returning(|_, _| Ok(Default::default()))
633
+ .times(1);
634
+
635
+ let retry_client = RetryClient::new(mock_client, Default::default());
636
+ let result = retry_client
637
+ .cancel_activity_task(vec![1].into(), None)
638
+ .await;
639
+ // Expecting successful response after retries
640
+ assert!(result.is_ok());
641
+ }
642
+ }
643
+
644
+ #[tokio::test]
645
+ async fn long_poll_retries_forever() {
646
+ // A bit odd, but we don't need a real client to test the retry client passes through the
647
+ // correct retry config
648
+ let fake_retry = RetryClient::new((), Default::default());
649
+ for i in 1..=50 {
650
+ for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
651
+ let mut err_handler =
652
+ TonicErrorHandler::new(fake_retry.get_retry_config(call), call);
653
+ let result = err_handler.handle(i, Status::new(Code::Unknown, "Ahh"));
654
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
655
+ }
656
+ }
657
+ }
658
+
659
+ #[tokio::test]
660
+ async fn long_poll_retries_deadline_exceeded() {
661
+ let fake_retry = RetryClient::new((), Default::default());
662
+ // For some reason we will get cancelled in these situations occasionally (always?) too
663
+ for code in [Code::Cancelled, Code::DeadlineExceeded] {
664
+ for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
665
+ let mut err_handler =
666
+ TonicErrorHandler::new(fake_retry.get_retry_config(call), call);
667
+ for i in 1..=5 {
668
+ let result = err_handler.handle(i, Status::new(code, "retryable failure"));
669
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
670
+ }
671
+ }
672
+ }
673
+ }
674
+ }