temporalio 0.0.0 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (327) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +301 -0
  3. data/bridge/Cargo.lock +2888 -0
  4. data/bridge/Cargo.toml +27 -0
  5. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  6. data/bridge/sdk-core/Cargo.lock +2606 -0
  7. data/bridge/sdk-core/Cargo.toml +2 -0
  8. data/bridge/sdk-core/LICENSE.txt +23 -0
  9. data/bridge/sdk-core/README.md +104 -0
  10. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  11. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  13. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  14. data/bridge/sdk-core/client/Cargo.toml +40 -0
  15. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  16. data/bridge/sdk-core/client/src/lib.rs +1286 -0
  17. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  18. data/bridge/sdk-core/client/src/raw.rs +932 -0
  19. data/bridge/sdk-core/client/src/retry.rs +751 -0
  20. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  21. data/bridge/sdk-core/core/Cargo.toml +116 -0
  22. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  23. data/bridge/sdk-core/core/benches/workflow_replay.rs +76 -0
  24. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  25. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -0
  26. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  27. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  28. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +925 -0
  29. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  30. data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -0
  31. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  32. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  33. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  34. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2090 -0
  35. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  36. data/bridge/sdk-core/core/src/lib.rs +282 -0
  37. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  38. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  39. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  40. data/bridge/sdk-core/core/src/replay/mod.rs +215 -0
  41. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  42. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  43. data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
  44. data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
  45. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
  46. data/bridge/sdk-core/core/src/test_help/mod.rs +889 -0
  47. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  48. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1048 -0
  49. data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
  50. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  51. data/bridge/sdk-core/core/src/worker/client.rs +373 -0
  52. data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
  53. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  54. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
  55. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
  60. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1200 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +655 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +985 -0
  80. data/bridge/sdk-core/core-api/Cargo.toml +32 -0
  81. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  82. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  83. data/bridge/sdk-core/core-api/src/lib.rs +109 -0
  84. data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
  85. data/bridge/sdk-core/core-api/src/worker.rs +148 -0
  86. data/bridge/sdk-core/etc/deps.svg +162 -0
  87. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  88. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  89. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  90. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  91. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  92. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  93. data/bridge/sdk-core/fsm/README.md +3 -0
  94. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  95. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  96. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  97. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  98. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  99. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  100. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  115. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  116. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  117. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  118. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  119. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  120. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  121. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  122. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  123. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  124. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  125. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  126. data/bridge/sdk-core/protos/api_upstream/buf.yaml +9 -0
  127. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  128. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  129. data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
  130. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  131. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  132. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +47 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +56 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +40 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +758 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +121 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +379 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -0
  164. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  165. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  166. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +263 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  174. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  175. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  176. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  179. data/bridge/sdk-core/rustfmt.toml +1 -0
  180. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  181. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  182. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  183. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  184. data/bridge/sdk-core/sdk/src/interceptors.rs +50 -0
  185. data/bridge/sdk-core/sdk/src/lib.rs +794 -0
  186. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  187. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  188. data/bridge/sdk-core/sdk/src/workflow_context.rs +694 -0
  189. data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -0
  190. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  191. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  192. data/bridge/sdk-core/sdk-core-protos/build.rs +107 -0
  193. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  194. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
  195. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  196. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  199. data/bridge/sdk-core/test-utils/Cargo.toml +36 -0
  200. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  201. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  202. data/bridge/sdk-core/test-utils/src/lib.rs +650 -0
  203. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  204. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  205. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +221 -0
  206. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  207. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -0
  208. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  209. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  210. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  211. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  212. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +788 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +223 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +597 -0
  227. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  228. data/bridge/sdk-core/tests/main.rs +113 -0
  229. data/bridge/sdk-core/tests/runner.rs +93 -0
  230. data/bridge/src/connection.rs +186 -0
  231. data/bridge/src/lib.rs +239 -0
  232. data/bridge/src/runtime.rs +54 -0
  233. data/bridge/src/worker.rs +124 -0
  234. data/ext/Rakefile +9 -0
  235. data/lib/bridge.so +0 -0
  236. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  237. data/lib/gen/temporal/api/batch/v1/message_pb.rb +50 -0
  238. data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
  239. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  240. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
  241. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
  242. data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
  243. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
  244. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
  245. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -0
  246. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  247. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  248. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  249. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  250. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  251. data/lib/gen/temporal/api/enums/v1/update_pb.rb +23 -0
  252. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  253. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  254. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  255. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  256. data/lib/gen/temporal/api/history/v1/message_pb.rb +490 -0
  257. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
  258. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  259. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -0
  260. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  261. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  262. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  263. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +149 -0
  264. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  265. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  266. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
  267. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -0
  268. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  269. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  270. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  271. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  272. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  273. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  274. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  275. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  276. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +165 -0
  277. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
  278. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  279. data/lib/temporalio/activity/context.rb +97 -0
  280. data/lib/temporalio/activity/info.rb +67 -0
  281. data/lib/temporalio/activity.rb +85 -0
  282. data/lib/temporalio/bridge/error.rb +8 -0
  283. data/lib/temporalio/bridge.rb +14 -0
  284. data/lib/temporalio/client/implementation.rb +340 -0
  285. data/lib/temporalio/client/workflow_handle.rb +243 -0
  286. data/lib/temporalio/client.rb +131 -0
  287. data/lib/temporalio/connection.rb +751 -0
  288. data/lib/temporalio/data_converter.rb +191 -0
  289. data/lib/temporalio/error/failure.rb +194 -0
  290. data/lib/temporalio/error/workflow_failure.rb +19 -0
  291. data/lib/temporalio/errors.rb +40 -0
  292. data/lib/temporalio/failure_converter/base.rb +26 -0
  293. data/lib/temporalio/failure_converter/basic.rb +319 -0
  294. data/lib/temporalio/failure_converter.rb +7 -0
  295. data/lib/temporalio/interceptor/chain.rb +28 -0
  296. data/lib/temporalio/interceptor/client.rb +123 -0
  297. data/lib/temporalio/payload_codec/base.rb +32 -0
  298. data/lib/temporalio/payload_converter/base.rb +24 -0
  299. data/lib/temporalio/payload_converter/bytes.rb +27 -0
  300. data/lib/temporalio/payload_converter/composite.rb +49 -0
  301. data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
  302. data/lib/temporalio/payload_converter/json.rb +26 -0
  303. data/lib/temporalio/payload_converter/nil.rb +26 -0
  304. data/lib/temporalio/payload_converter.rb +14 -0
  305. data/lib/temporalio/retry_policy.rb +82 -0
  306. data/lib/temporalio/retry_state.rb +35 -0
  307. data/lib/temporalio/runtime.rb +25 -0
  308. data/lib/temporalio/timeout_type.rb +29 -0
  309. data/lib/temporalio/version.rb +3 -0
  310. data/lib/temporalio/worker/activity_runner.rb +92 -0
  311. data/lib/temporalio/worker/activity_worker.rb +138 -0
  312. data/lib/temporalio/worker/reactor.rb +46 -0
  313. data/lib/temporalio/worker/runner.rb +63 -0
  314. data/lib/temporalio/worker/sync_worker.rb +88 -0
  315. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  316. data/lib/temporalio/worker.rb +198 -0
  317. data/lib/temporalio/workflow/execution_info.rb +54 -0
  318. data/lib/temporalio/workflow/execution_status.rb +36 -0
  319. data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
  320. data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
  321. data/lib/temporalio.rb +12 -1
  322. data/lib/thermite_patch.rb +23 -0
  323. data/temporalio.gemspec +45 -0
  324. metadata +566 -9
  325. data/lib/temporal/version.rb +0 -3
  326. data/lib/temporal.rb +0 -4
  327. data/temporal.gemspec +0 -20
@@ -0,0 +1,788 @@
1
+ use anyhow::anyhow;
2
+ use futures::future::join_all;
3
+ use futures_util::stream::{FuturesUnordered, StreamExt};
4
+ use std::{
5
+ sync::atomic::{AtomicU8, Ordering},
6
+ time::Duration,
7
+ };
8
+ use temporal_client::{WorkflowClientTrait, WorkflowOptions};
9
+ use temporal_sdk::{
10
+ interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, ActivityOptions,
11
+ CancellableFuture, LocalActivityOptions, WfContext, WorkflowResult,
12
+ };
13
+ use temporal_sdk_core::replay::HistoryForReplay;
14
+ use temporal_sdk_core_protos::{
15
+ coresdk::{
16
+ workflow_commands::ActivityCancellationType,
17
+ workflow_completion::WorkflowActivationCompletion, AsJsonPayloadExt,
18
+ },
19
+ temporal::api::{common::v1::RetryPolicy, enums::v1::TimeoutType},
20
+ TestHistoryBuilder,
21
+ };
22
+ use temporal_sdk_core_test_utils::{
23
+ history_from_proto_binary, init_integ_telem, replay_sdk_worker, CoreWfStarter,
24
+ };
25
+ use tokio_util::sync::CancellationToken;
26
+
27
+ pub async fn echo(_ctx: ActContext, e: String) -> anyhow::Result<String> {
28
+ Ok(e)
29
+ }
30
+
31
+ pub async fn one_local_activity_wf(ctx: WfContext) -> WorkflowResult<()> {
32
+ let initial_workflow_time = ctx.workflow_time().expect("Workflow time should be set");
33
+ ctx.local_activity(LocalActivityOptions {
34
+ activity_type: "echo_activity".to_string(),
35
+ input: "hi!".as_json_payload().expect("serializes fine"),
36
+ ..Default::default()
37
+ })
38
+ .await;
39
+ // Verify LA execution advances the clock
40
+ assert!(initial_workflow_time < ctx.workflow_time().unwrap());
41
+ Ok(().into())
42
+ }
43
+
44
+ #[tokio::test]
45
+ async fn one_local_activity() {
46
+ let wf_name = "one_local_activity";
47
+ let mut starter = CoreWfStarter::new(wf_name);
48
+ let mut worker = starter.worker().await;
49
+ worker.register_wf(wf_name.to_owned(), one_local_activity_wf);
50
+ worker.register_activity("echo_activity", echo);
51
+
52
+ worker
53
+ .submit_wf(
54
+ wf_name.to_owned(),
55
+ wf_name.to_owned(),
56
+ vec![],
57
+ WorkflowOptions::default(),
58
+ )
59
+ .await
60
+ .unwrap();
61
+ worker.run_until_done().await.unwrap();
62
+ }
63
+
64
+ pub async fn local_act_concurrent_with_timer_wf(ctx: WfContext) -> WorkflowResult<()> {
65
+ let la = ctx.local_activity(LocalActivityOptions {
66
+ activity_type: "echo_activity".to_string(),
67
+ input: "hi!".as_json_payload().expect("serializes fine"),
68
+ ..Default::default()
69
+ });
70
+ let timer = ctx.timer(Duration::from_secs(1));
71
+ tokio::join!(la, timer);
72
+ Ok(().into())
73
+ }
74
+
75
+ #[tokio::test]
76
+ async fn local_act_concurrent_with_timer() {
77
+ let wf_name = "local_act_concurrent_with_timer";
78
+ let mut starter = CoreWfStarter::new(wf_name);
79
+ let mut worker = starter.worker().await;
80
+ worker.register_wf(wf_name.to_owned(), local_act_concurrent_with_timer_wf);
81
+ worker.register_activity("echo_activity", echo);
82
+
83
+ worker
84
+ .submit_wf(
85
+ wf_name.to_owned(),
86
+ wf_name.to_owned(),
87
+ vec![],
88
+ WorkflowOptions::default(),
89
+ )
90
+ .await
91
+ .unwrap();
92
+ worker.run_until_done().await.unwrap();
93
+ }
94
+
95
+ pub async fn local_act_then_timer_then_wait(ctx: WfContext) -> WorkflowResult<()> {
96
+ let la = ctx.local_activity(LocalActivityOptions {
97
+ activity_type: "echo_activity".to_string(),
98
+ input: "hi!".as_json_payload().expect("serializes fine"),
99
+ ..Default::default()
100
+ });
101
+ ctx.timer(Duration::from_secs(1)).await;
102
+ let res = la.await;
103
+ assert!(res.completed_ok());
104
+ Ok(().into())
105
+ }
106
+
107
+ #[tokio::test]
108
+ async fn local_act_then_timer_then_wait_result() {
109
+ let wf_name = "local_act_then_timer_then_wait_result";
110
+ let mut starter = CoreWfStarter::new(wf_name);
111
+ let mut worker = starter.worker().await;
112
+ worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
113
+ worker.register_activity("echo_activity", echo);
114
+
115
+ worker
116
+ .submit_wf(
117
+ wf_name.to_owned(),
118
+ wf_name.to_owned(),
119
+ vec![],
120
+ WorkflowOptions::default(),
121
+ )
122
+ .await
123
+ .unwrap();
124
+ worker.run_until_done().await.unwrap();
125
+ }
126
+
127
+ #[tokio::test]
128
+ async fn long_running_local_act_with_timer() {
129
+ let wf_name = "long_running_local_act_with_timer";
130
+ let mut starter = CoreWfStarter::new(wf_name);
131
+ starter.wft_timeout(Duration::from_secs(1));
132
+ let mut worker = starter.worker().await;
133
+ worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
134
+ worker.register_activity("echo_activity", |_ctx: ActContext, str: String| async {
135
+ tokio::time::sleep(Duration::from_secs(4)).await;
136
+ Ok(str)
137
+ });
138
+
139
+ worker
140
+ .submit_wf(
141
+ wf_name.to_owned(),
142
+ wf_name.to_owned(),
143
+ vec![],
144
+ WorkflowOptions::default(),
145
+ )
146
+ .await
147
+ .unwrap();
148
+ worker.run_until_done().await.unwrap();
149
+ }
150
+
151
+ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
152
+ let las: Vec<_> = (1..=50)
153
+ .map(|i| {
154
+ ctx.local_activity(LocalActivityOptions {
155
+ activity_type: "echo_activity".to_string(),
156
+ input: format!("Hi {}", i)
157
+ .as_json_payload()
158
+ .expect("serializes fine"),
159
+ ..Default::default()
160
+ })
161
+ })
162
+ .collect();
163
+ ctx.timer(Duration::from_secs(1)).await;
164
+ join_all(las).await;
165
+ Ok(().into())
166
+ }
167
+
168
+ #[tokio::test]
169
+ async fn local_act_fanout() {
170
+ let wf_name = "local_act_fanout";
171
+ let mut starter = CoreWfStarter::new(wf_name);
172
+ starter.max_local_at(1);
173
+ let mut worker = starter.worker().await;
174
+ worker.register_wf(wf_name.to_owned(), local_act_fanout_wf);
175
+ worker.register_activity("echo_activity", echo);
176
+
177
+ worker
178
+ .submit_wf(
179
+ wf_name.to_owned(),
180
+ wf_name.to_owned(),
181
+ vec![],
182
+ WorkflowOptions::default(),
183
+ )
184
+ .await
185
+ .unwrap();
186
+ worker.run_until_done().await.unwrap();
187
+ }
188
+
189
+ #[tokio::test]
190
+ async fn local_act_retry_timer_backoff() {
191
+ let wf_name = "local_act_retry_timer_backoff";
192
+ let mut starter = CoreWfStarter::new(wf_name);
193
+ let mut worker = starter.worker().await;
194
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
195
+ let res = ctx
196
+ .local_activity(LocalActivityOptions {
197
+ activity_type: "echo".to_string(),
198
+ input: "hi".as_json_payload().expect("serializes fine"),
199
+ retry_policy: RetryPolicy {
200
+ initial_interval: Some(prost_dur!(from_micros(15))),
201
+ // We want two local backoffs that are short. Third backoff will use timer
202
+ backoff_coefficient: 1_000.,
203
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
204
+ maximum_attempts: 4,
205
+ non_retryable_error_types: vec![],
206
+ },
207
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
208
+ ..Default::default()
209
+ })
210
+ .await;
211
+ assert!(res.failed());
212
+ Ok(().into())
213
+ });
214
+ worker.register_activity("echo", |_: ActContext, _: String| async {
215
+ Result::<(), _>::Err(anyhow!("Oh no I failed!"))
216
+ });
217
+
218
+ let run_id = worker
219
+ .submit_wf(
220
+ wf_name.to_owned(),
221
+ wf_name.to_owned(),
222
+ vec![],
223
+ WorkflowOptions::default(),
224
+ )
225
+ .await
226
+ .unwrap();
227
+ worker.run_until_done().await.unwrap();
228
+ starter
229
+ .fetch_history_and_replay(wf_name, run_id, worker.inner_mut())
230
+ .await
231
+ .unwrap();
232
+ }
233
+
234
+ #[rstest::rstest]
235
+ #[case::wait(ActivityCancellationType::WaitCancellationCompleted)]
236
+ #[case::try_cancel(ActivityCancellationType::TryCancel)]
237
+ #[case::abandon(ActivityCancellationType::Abandon)]
238
+ #[tokio::test]
239
+ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
240
+ let wf_name = format!("cancel_immediate_{:?}", cancel_type);
241
+ let mut starter = CoreWfStarter::new(&wf_name);
242
+ let mut worker = starter.worker().await;
243
+ worker.register_wf(&wf_name, move |ctx: WfContext| async move {
244
+ let la = ctx.local_activity(LocalActivityOptions {
245
+ activity_type: "echo".to_string(),
246
+ input: "hi".as_json_payload().expect("serializes fine"),
247
+ cancel_type,
248
+ ..Default::default()
249
+ });
250
+ la.cancel(&ctx);
251
+ let resolution = la.await;
252
+ assert!(resolution.cancelled());
253
+ Ok(().into())
254
+ });
255
+
256
+ // If we don't use this, we'd hang on shutdown for abandon cancel modes.
257
+ let manual_cancel = CancellationToken::new();
258
+ let manual_cancel_act = manual_cancel.clone();
259
+
260
+ worker.register_activity("echo", move |ctx: ActContext, _: String| {
261
+ let manual_cancel_act = manual_cancel_act.clone();
262
+ async move {
263
+ tokio::select! {
264
+ _ = tokio::time::sleep(Duration::from_secs(10)) => {},
265
+ _ = ctx.cancelled() => {
266
+ return Err(anyhow!(ActivityCancelledError::default()))
267
+ }
268
+ _ = manual_cancel_act.cancelled() => {}
269
+ }
270
+ Ok(())
271
+ }
272
+ });
273
+
274
+ worker
275
+ .submit_wf(
276
+ wf_name.to_owned(),
277
+ wf_name.to_owned(),
278
+ vec![],
279
+ WorkflowOptions::default(),
280
+ )
281
+ .await
282
+ .unwrap();
283
+ worker
284
+ .run_until_done_intercepted(Some(LACancellerInterceptor {
285
+ token: manual_cancel,
286
+ }))
287
+ .await
288
+ .unwrap();
289
+ }
290
+
291
+ struct LACancellerInterceptor {
292
+ token: CancellationToken,
293
+ }
294
+ #[async_trait::async_trait(?Send)]
295
+ impl WorkerInterceptor for LACancellerInterceptor {
296
+ async fn on_workflow_activation_completion(&self, _: &WorkflowActivationCompletion) {}
297
+ fn on_shutdown(&self, _: &temporal_sdk::Worker) {
298
+ self.token.cancel()
299
+ }
300
+ }
301
+
302
+ #[rstest::rstest]
303
+ #[case::while_running(None)]
304
+ #[case::while_backing_off(Some(Duration::from_millis(1500)))]
305
+ #[case::while_backing_off_locally(Some(Duration::from_millis(150)))]
306
+ #[tokio::test]
307
+ async fn cancel_after_act_starts(
308
+ #[case] cancel_on_backoff: Option<Duration>,
309
+ #[values(
310
+ ActivityCancellationType::WaitCancellationCompleted,
311
+ ActivityCancellationType::TryCancel,
312
+ ActivityCancellationType::Abandon
313
+ )]
314
+ cancel_type: ActivityCancellationType,
315
+ ) {
316
+ let wf_name = format!(
317
+ "cancel_after_act_starts_timer_{:?}_{:?}",
318
+ cancel_on_backoff, cancel_type
319
+ );
320
+ let mut starter = CoreWfStarter::new(&wf_name);
321
+ starter.wft_timeout(Duration::from_secs(1));
322
+ let mut worker = starter.worker().await;
323
+ let bo_dur = cancel_on_backoff.unwrap_or_else(|| Duration::from_secs(1));
324
+ worker.register_wf(&wf_name, move |ctx: WfContext| async move {
325
+ let la = ctx.local_activity(LocalActivityOptions {
326
+ activity_type: "echo".to_string(),
327
+ input: "hi".as_json_payload().expect("serializes fine"),
328
+ retry_policy: RetryPolicy {
329
+ initial_interval: Some(bo_dur.try_into().unwrap()),
330
+ backoff_coefficient: 1.,
331
+ maximum_interval: Some(bo_dur.try_into().unwrap()),
332
+ // Retry forever until cancelled
333
+ ..Default::default()
334
+ },
335
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
336
+ cancel_type,
337
+ ..Default::default()
338
+ });
339
+ ctx.timer(Duration::from_secs(1)).await;
340
+ // Note that this cancel can't go through for *two* WF tasks, because we do a full heartbeat
341
+ // before the timer (LA hasn't resolved), and then the timer fired event won't appear in
342
+ // history until *after* the next WFT because we force generated it when we sent the timer
343
+ // command.
344
+ la.cancel(&ctx);
345
+ // This extra timer is here to ensure the presence of another WF task doesn't mess up
346
+ // resolving the LA with cancel on replay
347
+ ctx.timer(Duration::from_secs(1)).await;
348
+ let resolution = la.await;
349
+ assert!(resolution.cancelled());
350
+ Ok(().into())
351
+ });
352
+
353
+ // If we don't use this, we'd hang on shutdown for abandon cancel modes.
354
+ let manual_cancel = CancellationToken::new();
355
+ let manual_cancel_act = manual_cancel.clone();
356
+
357
+ worker.register_activity("echo", move |ctx: ActContext, _: String| {
358
+ let manual_cancel_act = manual_cancel_act.clone();
359
+ async move {
360
+ if cancel_on_backoff.is_some() {
361
+ if ctx.is_cancelled() {
362
+ return Err(anyhow!(ActivityCancelledError::default()));
363
+ }
364
+ // Just fail constantly so we get stuck on the backoff timer
365
+ return Err(anyhow!("Oh no I failed!"));
366
+ } else {
367
+ tokio::select! {
368
+ _ = tokio::time::sleep(Duration::from_secs(100)) => {},
369
+ _ = ctx.cancelled() => {
370
+ return Err(anyhow!(ActivityCancelledError::default()))
371
+ }
372
+ _ = manual_cancel_act.cancelled() => {
373
+ return Ok(())
374
+ }
375
+ }
376
+ }
377
+ Err(anyhow!("Oh no I failed!"))
378
+ }
379
+ });
380
+
381
+ worker
382
+ .submit_wf(
383
+ wf_name.to_owned(),
384
+ wf_name.to_owned(),
385
+ vec![],
386
+ WorkflowOptions::default(),
387
+ )
388
+ .await
389
+ .unwrap();
390
+ worker
391
+ .run_until_done_intercepted(Some(LACancellerInterceptor {
392
+ token: manual_cancel,
393
+ }))
394
+ .await
395
+ .unwrap();
396
+ }
397
+
398
+ #[rstest::rstest]
399
+ #[case::schedule(true)]
400
+ #[case::start(false)]
401
+ #[tokio::test]
402
+ async fn x_to_close_timeout(#[case] is_schedule: bool) {
403
+ let wf_name = format!(
404
+ "{}_to_close_timeout",
405
+ if is_schedule { "schedule" } else { "start" }
406
+ );
407
+ let mut starter = CoreWfStarter::new(&wf_name);
408
+ let mut worker = starter.worker().await;
409
+ let (sched, start) = if is_schedule {
410
+ (Some(Duration::from_secs(2)), None)
411
+ } else {
412
+ (None, Some(Duration::from_secs(2)))
413
+ };
414
+ let timeout_type = if is_schedule {
415
+ TimeoutType::ScheduleToClose
416
+ } else {
417
+ TimeoutType::StartToClose
418
+ };
419
+
420
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
421
+ let res = ctx
422
+ .local_activity(LocalActivityOptions {
423
+ activity_type: "echo".to_string(),
424
+ input: "hi".as_json_payload().expect("serializes fine"),
425
+ retry_policy: RetryPolicy {
426
+ initial_interval: Some(prost_dur!(from_micros(15))),
427
+ backoff_coefficient: 1_000.,
428
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
429
+ maximum_attempts: 4,
430
+ non_retryable_error_types: vec![],
431
+ },
432
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
433
+ schedule_to_close_timeout: sched,
434
+ start_to_close_timeout: start,
435
+ ..Default::default()
436
+ })
437
+ .await;
438
+ assert_eq!(res.timed_out(), Some(timeout_type));
439
+ Ok(().into())
440
+ });
441
+ worker.register_activity("echo", |ctx: ActContext, _: String| async move {
442
+ tokio::select! {
443
+ _ = tokio::time::sleep(Duration::from_secs(100)) => {},
444
+ _ = ctx.cancelled() => {
445
+ return Err(anyhow!(ActivityCancelledError::default()))
446
+ }
447
+ };
448
+ Ok(())
449
+ });
450
+
451
+ worker
452
+ .submit_wf(
453
+ wf_name.to_owned(),
454
+ wf_name.to_owned(),
455
+ vec![],
456
+ WorkflowOptions::default(),
457
+ )
458
+ .await
459
+ .unwrap();
460
+ worker.run_until_done().await.unwrap();
461
+ }
462
+
463
+ #[rstest::rstest]
464
+ #[case::cached(true)]
465
+ #[case::not_cached(false)]
466
+ #[tokio::test]
467
+ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
468
+ let wf_name = format!(
469
+ "schedule_to_close_timeout_across_timer_backoff_{}",
470
+ if cached { "cached" } else { "not_cached" }
471
+ );
472
+ let mut starter = CoreWfStarter::new(&wf_name);
473
+ if !cached {
474
+ starter.max_cached_workflows(0);
475
+ }
476
+ let mut worker = starter.worker().await;
477
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
478
+ let res = ctx
479
+ .local_activity(LocalActivityOptions {
480
+ activity_type: "echo".to_string(),
481
+ input: "hi".as_json_payload().expect("serializes fine"),
482
+ retry_policy: RetryPolicy {
483
+ initial_interval: Some(prost_dur!(from_millis(15))),
484
+ backoff_coefficient: 1_000.,
485
+ maximum_interval: Some(prost_dur!(from_millis(1000))),
486
+ maximum_attempts: 40,
487
+ non_retryable_error_types: vec![],
488
+ },
489
+ timer_backoff_threshold: Some(Duration::from_millis(500)),
490
+ schedule_to_close_timeout: Some(Duration::from_secs(2)),
491
+ ..Default::default()
492
+ })
493
+ .await;
494
+ assert_eq!(res.timed_out(), Some(TimeoutType::ScheduleToClose));
495
+ Ok(().into())
496
+ });
497
+ let num_attempts: &'static _ = Box::leak(Box::new(AtomicU8::new(0)));
498
+ worker.register_activity("echo", move |_: ActContext, _: String| async {
499
+ num_attempts.fetch_add(1, Ordering::Relaxed);
500
+ Result::<(), _>::Err(anyhow!("Oh no I failed!"))
501
+ });
502
+
503
+ worker
504
+ .submit_wf(
505
+ wf_name.to_owned(),
506
+ wf_name.to_owned(),
507
+ vec![],
508
+ WorkflowOptions::default(),
509
+ )
510
+ .await
511
+ .unwrap();
512
+ worker.run_until_done().await.unwrap();
513
+ // 3 attempts b/c first backoff is very small, then the next 2 attempts take at least 2 seconds
514
+ // b/c of timer backoff.
515
+ assert_eq!(3, num_attempts.load(Ordering::Relaxed));
516
+ }
517
+
518
+ #[rstest::rstest]
519
+ #[tokio::test]
520
+ async fn eviction_wont_make_local_act_get_dropped(#[values(true, false)] short_wft_timeout: bool) {
521
+ let wf_name = format!(
522
+ "eviction_wont_make_local_act_get_dropped_{}",
523
+ short_wft_timeout
524
+ );
525
+ let mut starter = CoreWfStarter::new(&wf_name);
526
+ starter.max_cached_workflows(0);
527
+ let mut worker = starter.worker().await;
528
+ worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
529
+ worker.register_activity("echo_activity", |_ctx: ActContext, str: String| async {
530
+ tokio::time::sleep(Duration::from_secs(4)).await;
531
+ Ok(str)
532
+ });
533
+
534
+ let opts = if short_wft_timeout {
535
+ WorkflowOptions {
536
+ task_timeout: Some(Duration::from_secs(1)),
537
+ ..Default::default()
538
+ }
539
+ } else {
540
+ Default::default()
541
+ };
542
+ worker
543
+ .submit_wf(wf_name.to_owned(), wf_name.to_owned(), vec![], opts)
544
+ .await
545
+ .unwrap();
546
+ worker.run_until_done().await.unwrap();
547
+ }
548
+
549
+ #[tokio::test]
550
+ async fn timer_backoff_concurrent_with_non_timer_backoff() {
551
+ let wf_name = "timer_backoff_concurrent_with_non_timer_backoff";
552
+ let mut starter = CoreWfStarter::new(wf_name);
553
+ let mut worker = starter.worker().await;
554
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
555
+ let r1 = ctx.local_activity(LocalActivityOptions {
556
+ activity_type: "echo".to_string(),
557
+ input: "hi".as_json_payload().expect("serializes fine"),
558
+ retry_policy: RetryPolicy {
559
+ initial_interval: Some(prost_dur!(from_micros(15))),
560
+ backoff_coefficient: 1_000.,
561
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
562
+ maximum_attempts: 4,
563
+ non_retryable_error_types: vec![],
564
+ },
565
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
566
+ ..Default::default()
567
+ });
568
+ let r2 = ctx.local_activity(LocalActivityOptions {
569
+ activity_type: "echo".to_string(),
570
+ input: "hi".as_json_payload().expect("serializes fine"),
571
+ retry_policy: RetryPolicy {
572
+ initial_interval: Some(prost_dur!(from_millis(15))),
573
+ backoff_coefficient: 10.,
574
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
575
+ maximum_attempts: 4,
576
+ non_retryable_error_types: vec![],
577
+ },
578
+ timer_backoff_threshold: Some(Duration::from_secs(10)),
579
+ ..Default::default()
580
+ });
581
+ let (r1, r2) = tokio::join!(r1, r2);
582
+ assert!(r1.failed());
583
+ assert!(r2.failed());
584
+ Ok(().into())
585
+ });
586
+ worker.register_activity("echo", |_: ActContext, _: String| async {
587
+ Result::<(), _>::Err(anyhow!("Oh no I failed!"))
588
+ });
589
+
590
+ worker
591
+ .submit_wf(
592
+ wf_name.to_owned(),
593
+ wf_name.to_owned(),
594
+ vec![],
595
+ WorkflowOptions::default(),
596
+ )
597
+ .await
598
+ .unwrap();
599
+ worker.run_until_done().await.unwrap();
600
+ }
601
+
602
+ #[tokio::test]
603
+ async fn repro_nondeterminism_with_timer_bug() {
604
+ let wf_name = "repro_nondeterminism_with_timer_bug";
605
+ let mut starter = CoreWfStarter::new(wf_name);
606
+ let mut worker = starter.worker().await;
607
+
608
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
609
+ let t1 = ctx.timer(Duration::from_secs(30));
610
+ let r1 = ctx.local_activity(LocalActivityOptions {
611
+ activity_type: "delay".to_string(),
612
+ input: "hi".as_json_payload().expect("serializes fine"),
613
+ retry_policy: RetryPolicy {
614
+ initial_interval: Some(prost_dur!(from_micros(15))),
615
+ backoff_coefficient: 1_000.,
616
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
617
+ maximum_attempts: 4,
618
+ non_retryable_error_types: vec![],
619
+ },
620
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
621
+ ..Default::default()
622
+ });
623
+ tokio::pin!(t1);
624
+ tokio::select! {
625
+ _ = &mut t1 => {},
626
+ _ = r1 => {
627
+ t1.cancel(&ctx);
628
+ },
629
+ };
630
+ ctx.timer(Duration::from_secs(1)).await;
631
+ Ok(().into())
632
+ });
633
+ worker.register_activity("delay", |_: ActContext, _: String| async {
634
+ tokio::time::sleep(Duration::from_secs(2)).await;
635
+ Ok(())
636
+ });
637
+
638
+ let run_id = worker
639
+ .submit_wf(
640
+ wf_name.to_owned(),
641
+ wf_name.to_owned(),
642
+ vec![],
643
+ WorkflowOptions::default(),
644
+ )
645
+ .await
646
+ .unwrap();
647
+ worker.run_until_done().await.unwrap();
648
+ starter
649
+ .fetch_history_and_replay(wf_name, run_id, worker.inner_mut())
650
+ .await
651
+ .unwrap();
652
+ }
653
+
654
+ async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
655
+ ctx.local_activity(LocalActivityOptions {
656
+ activity_type: "delay".to_string(),
657
+ input: "hi".as_json_payload().expect("serializes fine"),
658
+ retry_policy: RetryPolicy {
659
+ initial_interval: Some(prost_dur!(from_micros(15))),
660
+ backoff_coefficient: 1_000.,
661
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
662
+ maximum_attempts: 4,
663
+ non_retryable_error_types: vec![],
664
+ },
665
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
666
+ ..Default::default()
667
+ })
668
+ .await;
669
+ ctx.activity(ActivityOptions {
670
+ activity_type: "delay".to_string(),
671
+ start_to_close_timeout: Some(Duration::from_secs(20)),
672
+ input: "hi!".as_json_payload().expect("serializes fine"),
673
+ ..Default::default()
674
+ })
675
+ .await;
676
+ Ok(().into())
677
+ }
678
+
679
+ // Expensive to run - worth enabling on a stress/regression pipeline.
680
+ #[ignore]
681
+ #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
682
+ async fn evict_while_la_running_no_interference() {
683
+ let wf_name = "evict_while_la_running_no_interference";
684
+ let mut starter = CoreWfStarter::new(wf_name);
685
+ starter.max_local_at(20);
686
+ starter.max_cached_workflows(20);
687
+ let mut worker = starter.worker().await;
688
+
689
+ worker.register_wf(wf_name.to_owned(), la_problem_workflow);
690
+ worker.register_activity("delay", |_: ActContext, _: String| async {
691
+ tokio::time::sleep(Duration::from_secs(15)).await;
692
+ Ok(())
693
+ });
694
+
695
+ let client = starter.get_client().await;
696
+ let subfs = FuturesUnordered::new();
697
+ for i in 1..100 {
698
+ let wf_id = format!("{}-{}", wf_name, i);
699
+ let run_id = worker
700
+ .submit_wf(
701
+ &wf_id,
702
+ wf_name.to_owned(),
703
+ vec![],
704
+ WorkflowOptions::default(),
705
+ )
706
+ .await
707
+ .unwrap();
708
+ let cw = worker.core_worker.clone();
709
+ let client = client.clone();
710
+ subfs.push(async move {
711
+ // Evict the workflow
712
+ tokio::time::sleep(Duration::from_secs(1)).await;
713
+ cw.request_workflow_eviction(&run_id);
714
+ // Wake up workflow by sending signal
715
+ client
716
+ .signal_workflow_execution(
717
+ wf_id,
718
+ run_id.clone(),
719
+ "whaatever".to_string(),
720
+ None,
721
+ None,
722
+ )
723
+ .await
724
+ .unwrap();
725
+ });
726
+ }
727
+ let runf = async {
728
+ worker.run_until_done().await.unwrap();
729
+ };
730
+ tokio::join!(subfs.collect::<Vec<_>>(), runf);
731
+ }
732
+
733
+ #[rstest::rstest]
734
+ #[tokio::test]
735
+ async fn weird_la_nondeterminism_repro(#[values(true, false)] fix_hist: bool) {
736
+ init_integ_telem();
737
+ let mut hist = history_from_proto_binary(
738
+ "histories/evict_while_la_running_no_interference-85_history.bin",
739
+ )
740
+ .await
741
+ .unwrap();
742
+ if fix_hist {
743
+ // Replace broken ending with accurate ending
744
+ hist.events.truncate(20);
745
+ let mut thb = TestHistoryBuilder::from_history(hist.events);
746
+ thb.add_workflow_task_completed();
747
+ thb.add_workflow_execution_completed();
748
+ hist = thb.get_full_history_info().unwrap().into();
749
+ }
750
+
751
+ let mut worker = replay_sdk_worker([HistoryForReplay::new(hist, "fake".to_owned())]);
752
+ worker.register_wf(
753
+ "evict_while_la_running_no_interference",
754
+ la_problem_workflow,
755
+ );
756
+ worker.register_activity("delay", |_: ActContext, _: String| async {
757
+ tokio::time::sleep(Duration::from_secs(15)).await;
758
+ Ok(())
759
+ });
760
+ worker.run().await.unwrap();
761
+ }
762
+
763
+ #[tokio::test]
764
+ async fn second_weird_la_nondeterminism_repro() {
765
+ init_integ_telem();
766
+ let mut hist = history_from_proto_binary(
767
+ "histories/evict_while_la_running_no_interference-23_history.bin",
768
+ )
769
+ .await
770
+ .unwrap();
771
+ // Chop off uninteresting ending
772
+ hist.events.truncate(24);
773
+ let mut thb = TestHistoryBuilder::from_history(hist.events);
774
+ // thb.add_workflow_task_completed();
775
+ thb.add_workflow_execution_completed();
776
+ hist = thb.get_full_history_info().unwrap().into();
777
+
778
+ let mut worker = replay_sdk_worker([HistoryForReplay::new(hist, "fake".to_owned())]);
779
+ worker.register_wf(
780
+ "evict_while_la_running_no_interference",
781
+ la_problem_workflow,
782
+ );
783
+ worker.register_activity("delay", |_: ActContext, _: String| async {
784
+ tokio::time::sleep(Duration::from_secs(15)).await;
785
+ Ok(())
786
+ });
787
+ worker.run().await.unwrap();
788
+ }