temporalio 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +301 -0
  3. data/bridge/Cargo.lock +2888 -0
  4. data/bridge/Cargo.toml +27 -0
  5. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  6. data/bridge/sdk-core/Cargo.lock +2606 -0
  7. data/bridge/sdk-core/Cargo.toml +2 -0
  8. data/bridge/sdk-core/LICENSE.txt +23 -0
  9. data/bridge/sdk-core/README.md +104 -0
  10. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  11. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  13. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  14. data/bridge/sdk-core/client/Cargo.toml +40 -0
  15. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  16. data/bridge/sdk-core/client/src/lib.rs +1286 -0
  17. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  18. data/bridge/sdk-core/client/src/raw.rs +932 -0
  19. data/bridge/sdk-core/client/src/retry.rs +751 -0
  20. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  21. data/bridge/sdk-core/core/Cargo.toml +116 -0
  22. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  23. data/bridge/sdk-core/core/benches/workflow_replay.rs +76 -0
  24. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  25. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +1014 -0
  26. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  27. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  28. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +925 -0
  29. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  30. data/bridge/sdk-core/core/src/core_tests/queries.rs +894 -0
  31. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  32. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  33. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  34. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2090 -0
  35. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  36. data/bridge/sdk-core/core/src/lib.rs +282 -0
  37. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  38. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  39. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  40. data/bridge/sdk-core/core/src/replay/mod.rs +215 -0
  41. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  42. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  43. data/bridge/sdk-core/core/src/telemetry/metrics.rs +428 -0
  44. data/bridge/sdk-core/core/src/telemetry/mod.rs +407 -0
  45. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +78 -0
  46. data/bridge/sdk-core/core/src/test_help/mod.rs +889 -0
  47. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  48. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1048 -0
  49. data/bridge/sdk-core/core/src/worker/activities.rs +481 -0
  50. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  51. data/bridge/sdk-core/core/src/worker/client.rs +373 -0
  52. data/bridge/sdk-core/core/src/worker/mod.rs +570 -0
  53. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  54. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +101 -0
  55. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +532 -0
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +907 -0
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +294 -0
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +167 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +858 -0
  60. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +136 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +157 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +129 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1450 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +316 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +708 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +439 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +435 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +175 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +242 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1200 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +272 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +655 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1200 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +985 -0
  80. data/bridge/sdk-core/core-api/Cargo.toml +32 -0
  81. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  82. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  83. data/bridge/sdk-core/core-api/src/lib.rs +109 -0
  84. data/bridge/sdk-core/core-api/src/telemetry.rs +147 -0
  85. data/bridge/sdk-core/core-api/src/worker.rs +148 -0
  86. data/bridge/sdk-core/etc/deps.svg +162 -0
  87. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  88. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  89. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  90. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  91. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  92. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  93. data/bridge/sdk-core/fsm/README.md +3 -0
  94. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  95. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  96. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  97. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  98. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  99. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  100. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  115. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  116. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  117. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  118. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  119. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  120. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  121. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  122. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  123. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  124. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  125. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  126. data/bridge/sdk-core/protos/api_upstream/buf.yaml +9 -0
  127. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  128. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  129. data/bridge/sdk-core/protos/api_upstream/build/tools.go +29 -0
  130. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  131. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  132. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +89 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +260 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +47 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +56 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +170 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +118 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/interaction_type.proto +39 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +40 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +758 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +121 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +80 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +379 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +146 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1168 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +415 -0
  164. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  165. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  166. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +263 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +304 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  174. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  175. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  176. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  179. data/bridge/sdk-core/rustfmt.toml +1 -0
  180. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  181. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  182. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  183. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  184. data/bridge/sdk-core/sdk/src/interceptors.rs +50 -0
  185. data/bridge/sdk-core/sdk/src/lib.rs +794 -0
  186. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  187. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  188. data/bridge/sdk-core/sdk/src/workflow_context.rs +694 -0
  189. data/bridge/sdk-core/sdk/src/workflow_future.rs +499 -0
  190. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  191. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  192. data/bridge/sdk-core/sdk-core-protos/build.rs +107 -0
  193. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  194. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +544 -0
  195. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  196. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1970 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  199. data/bridge/sdk-core/test-utils/Cargo.toml +36 -0
  200. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  201. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  202. data/bridge/sdk-core/test-utils/src/lib.rs +650 -0
  203. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  204. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  205. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +221 -0
  206. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
  207. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +133 -0
  208. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  209. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  210. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  211. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  212. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +788 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +223 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +597 -0
  227. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  228. data/bridge/sdk-core/tests/main.rs +113 -0
  229. data/bridge/sdk-core/tests/runner.rs +93 -0
  230. data/bridge/src/connection.rs +186 -0
  231. data/bridge/src/lib.rs +239 -0
  232. data/bridge/src/runtime.rs +54 -0
  233. data/bridge/src/worker.rs +124 -0
  234. data/ext/Rakefile +9 -0
  235. data/lib/bridge.so +0 -0
  236. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  237. data/lib/gen/temporal/api/batch/v1/message_pb.rb +50 -0
  238. data/lib/gen/temporal/api/command/v1/message_pb.rb +174 -0
  239. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  240. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +33 -0
  241. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +39 -0
  242. data/lib/gen/temporal/api/enums/v1/common_pb.rb +42 -0
  243. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +68 -0
  244. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +77 -0
  245. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +25 -0
  246. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  247. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  248. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  249. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  250. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  251. data/lib/gen/temporal/api/enums/v1/update_pb.rb +23 -0
  252. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  253. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  254. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  255. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  256. data/lib/gen/temporal/api/history/v1/message_pb.rb +490 -0
  257. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +49 -0
  258. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  259. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +85 -0
  260. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  261. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  262. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  263. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +149 -0
  264. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  265. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  266. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +111 -0
  267. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +788 -0
  268. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  269. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  270. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  271. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  272. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  273. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  274. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  275. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  276. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +165 -0
  277. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +196 -0
  278. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  279. data/lib/temporalio/activity/context.rb +97 -0
  280. data/lib/temporalio/activity/info.rb +67 -0
  281. data/lib/temporalio/activity.rb +85 -0
  282. data/lib/temporalio/bridge/error.rb +8 -0
  283. data/lib/temporalio/bridge.rb +14 -0
  284. data/lib/temporalio/client/implementation.rb +340 -0
  285. data/lib/temporalio/client/workflow_handle.rb +243 -0
  286. data/lib/temporalio/client.rb +131 -0
  287. data/lib/temporalio/connection.rb +751 -0
  288. data/lib/temporalio/data_converter.rb +191 -0
  289. data/lib/temporalio/error/failure.rb +194 -0
  290. data/lib/temporalio/error/workflow_failure.rb +19 -0
  291. data/lib/temporalio/errors.rb +40 -0
  292. data/lib/temporalio/failure_converter/base.rb +26 -0
  293. data/lib/temporalio/failure_converter/basic.rb +319 -0
  294. data/lib/temporalio/failure_converter.rb +7 -0
  295. data/lib/temporalio/interceptor/chain.rb +28 -0
  296. data/lib/temporalio/interceptor/client.rb +123 -0
  297. data/lib/temporalio/payload_codec/base.rb +32 -0
  298. data/lib/temporalio/payload_converter/base.rb +24 -0
  299. data/lib/temporalio/payload_converter/bytes.rb +27 -0
  300. data/lib/temporalio/payload_converter/composite.rb +49 -0
  301. data/lib/temporalio/payload_converter/encoding_base.rb +35 -0
  302. data/lib/temporalio/payload_converter/json.rb +26 -0
  303. data/lib/temporalio/payload_converter/nil.rb +26 -0
  304. data/lib/temporalio/payload_converter.rb +14 -0
  305. data/lib/temporalio/retry_policy.rb +82 -0
  306. data/lib/temporalio/retry_state.rb +35 -0
  307. data/lib/temporalio/runtime.rb +25 -0
  308. data/lib/temporalio/timeout_type.rb +29 -0
  309. data/lib/temporalio/version.rb +3 -0
  310. data/lib/temporalio/worker/activity_runner.rb +92 -0
  311. data/lib/temporalio/worker/activity_worker.rb +138 -0
  312. data/lib/temporalio/worker/reactor.rb +46 -0
  313. data/lib/temporalio/worker/runner.rb +63 -0
  314. data/lib/temporalio/worker/sync_worker.rb +88 -0
  315. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  316. data/lib/temporalio/worker.rb +198 -0
  317. data/lib/temporalio/workflow/execution_info.rb +54 -0
  318. data/lib/temporalio/workflow/execution_status.rb +36 -0
  319. data/lib/temporalio/workflow/id_reuse_policy.rb +36 -0
  320. data/lib/temporalio/workflow/query_reject_condition.rb +33 -0
  321. data/lib/temporalio.rb +12 -1
  322. data/lib/thermite_patch.rb +23 -0
  323. data/temporalio.gemspec +45 -0
  324. metadata +566 -9
  325. data/lib/temporal/version.rb +0 -3
  326. data/lib/temporal.rb +0 -4
  327. data/temporal.gemspec +0 -20
@@ -0,0 +1,925 @@
1
+ use crate::{
2
+ prost_dur,
3
+ replay::{default_wes_attribs, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE},
4
+ test_help::{
5
+ hist_to_poll_resp, mock_sdk, mock_sdk_cfg, mock_worker, single_hist_mock_sg, MockPollCfg,
6
+ ResponseType,
7
+ },
8
+ worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
9
+ };
10
+ use anyhow::anyhow;
11
+ use futures::{future::join_all, FutureExt};
12
+ use std::{
13
+ collections::HashMap,
14
+ ops::Sub,
15
+ sync::{
16
+ atomic::{AtomicUsize, Ordering},
17
+ Arc,
18
+ },
19
+ time::{Duration, SystemTime},
20
+ };
21
+ use temporal_client::WorkflowOptions;
22
+ use temporal_sdk::{ActContext, LocalActivityOptions, WfContext, WorkflowResult};
23
+ use temporal_sdk_core_api::Worker;
24
+ use temporal_sdk_core_protos::{
25
+ coresdk::{
26
+ activity_result::ActivityExecutionResult,
27
+ workflow_activation::{workflow_activation_job, WorkflowActivationJob},
28
+ workflow_commands::{ActivityCancellationType, QueryResult, QuerySuccess},
29
+ workflow_completion::WorkflowActivationCompletion,
30
+ ActivityTaskCompletion, AsJsonPayloadExt,
31
+ },
32
+ temporal::api::{
33
+ common::v1::RetryPolicy,
34
+ enums::v1::{EventType, TimeoutType},
35
+ failure::v1::Failure,
36
+ history::v1::History,
37
+ query::v1::WorkflowQuery,
38
+ },
39
+ };
40
+ use temporal_sdk_core_test_utils::{
41
+ schedule_local_activity_cmd, start_timer_cmd, WorkerTestHelpers,
42
+ };
43
+ use tokio::sync::Barrier;
44
+
45
+ async fn echo(_ctx: ActContext, e: String) -> anyhow::Result<String> {
46
+ Ok(e)
47
+ }
48
+
49
+ /// This test verifies that when replaying we are able to resolve local activities whose data we
50
+ /// don't see until after the workflow issues the command
51
+ #[rstest::rstest]
52
+ #[case::replay(true, true)]
53
+ #[case::not_replay(false, true)]
54
+ #[case::replay_cache_off(true, false)]
55
+ #[case::not_replay_cache_off(false, false)]
56
+ #[tokio::test]
57
+ async fn local_act_two_wfts_before_marker(#[case] replay: bool, #[case] cached: bool) {
58
+ let mut t = TestHistoryBuilder::default();
59
+ t.add_by_type(EventType::WorkflowExecutionStarted);
60
+ t.add_full_wf_task();
61
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
62
+ t.add_full_wf_task();
63
+ t.add_local_activity_result_marker(1, "1", b"echo".into());
64
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
65
+ t.add_full_wf_task();
66
+ t.add_workflow_execution_completed();
67
+
68
+ let wf_id = "fakeid";
69
+ let mock = mock_workflow_client();
70
+ let resps = if replay {
71
+ vec![ResponseType::AllHistory]
72
+ } else {
73
+ vec![1.into(), 2.into(), ResponseType::AllHistory]
74
+ };
75
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, resps, mock);
76
+ let mut worker = mock_sdk_cfg(mh, |cfg| {
77
+ if cached {
78
+ cfg.max_cached_workflows = 1;
79
+ }
80
+ });
81
+
82
+ worker.register_wf(
83
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
84
+ |ctx: WfContext| async move {
85
+ let la = ctx.local_activity(LocalActivityOptions {
86
+ activity_type: "echo".to_string(),
87
+ input: "hi".as_json_payload().expect("serializes fine"),
88
+ ..Default::default()
89
+ });
90
+ ctx.timer(Duration::from_secs(1)).await;
91
+ la.await;
92
+ Ok(().into())
93
+ },
94
+ );
95
+ worker.register_activity("echo", echo);
96
+ worker
97
+ .submit_wf(
98
+ wf_id.to_owned(),
99
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
100
+ vec![],
101
+ WorkflowOptions::default(),
102
+ )
103
+ .await
104
+ .unwrap();
105
+ worker.run_until_done().await.unwrap();
106
+ }
107
+
108
+ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
109
+ let las: Vec<_> = (1..=50)
110
+ .map(|i| {
111
+ ctx.local_activity(LocalActivityOptions {
112
+ activity_type: "echo".to_string(),
113
+ input: format!("Hi {}", i)
114
+ .as_json_payload()
115
+ .expect("serializes fine"),
116
+ ..Default::default()
117
+ })
118
+ })
119
+ .collect();
120
+ ctx.timer(Duration::from_secs(1)).await;
121
+ join_all(las).await;
122
+ Ok(().into())
123
+ }
124
+
125
+ #[tokio::test]
126
+ async fn local_act_many_concurrent() {
127
+ let mut t = TestHistoryBuilder::default();
128
+ t.add_by_type(EventType::WorkflowExecutionStarted);
129
+ t.add_full_wf_task();
130
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
131
+ t.add_full_wf_task();
132
+ for i in 1..=50 {
133
+ t.add_local_activity_result_marker(i, &i.to_string(), b"echo".into());
134
+ }
135
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
136
+ t.add_full_wf_task();
137
+ t.add_workflow_execution_completed();
138
+
139
+ let wf_id = "fakeid";
140
+ let mock = mock_workflow_client();
141
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 3], mock);
142
+ let mut worker = mock_sdk(mh);
143
+
144
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE.to_owned(), local_act_fanout_wf);
145
+ worker.register_activity("echo", echo);
146
+ worker
147
+ .submit_wf(
148
+ wf_id.to_owned(),
149
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
150
+ vec![],
151
+ WorkflowOptions::default(),
152
+ )
153
+ .await
154
+ .unwrap();
155
+ worker.run_until_done().await.unwrap();
156
+ }
157
+
158
+ /// Verifies that local activities which take more than a workflow task timeout will cause
159
+ /// us to issue additional (empty) WFT completions with the force flag on, thus preventing timeout
160
+ /// of WFT while the local activity continues to execute.
161
+ ///
162
+ /// The test with shutdown verifies if we call shutdown while the local activity is running that
163
+ /// shutdown does not complete until it's finished.
164
+ #[rstest::rstest]
165
+ #[case::with_shutdown(true)]
166
+ #[case::normal_complete(false)]
167
+ #[tokio::test]
168
+ async fn local_act_heartbeat(#[case] shutdown_middle: bool) {
169
+ let mut t = TestHistoryBuilder::default();
170
+ let wft_timeout = Duration::from_millis(200);
171
+ let mut wes_short_wft_timeout = default_wes_attribs();
172
+ wes_short_wft_timeout.workflow_task_timeout = Some(wft_timeout.try_into().unwrap());
173
+ t.add(
174
+ EventType::WorkflowExecutionStarted,
175
+ wes_short_wft_timeout.into(),
176
+ );
177
+ t.add_full_wf_task();
178
+ // Task created by WFT heartbeat
179
+ t.add_full_wf_task();
180
+ t.add_workflow_task_scheduled_and_started();
181
+
182
+ let wf_id = "fakeid";
183
+ let mock = mock_workflow_client();
184
+ let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 2, 2], mock);
185
+ mh.enforce_correct_number_of_polls = false;
186
+ let mut worker = mock_sdk_cfg(mh, |wc| {
187
+ wc.max_cached_workflows = 1;
188
+ wc.max_outstanding_workflow_tasks = 1;
189
+ });
190
+ let core = worker.core_worker.clone();
191
+
192
+ let shutdown_barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
193
+
194
+ worker.register_wf(
195
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
196
+ |ctx: WfContext| async move {
197
+ ctx.local_activity(LocalActivityOptions {
198
+ activity_type: "echo".to_string(),
199
+ input: "hi".as_json_payload().expect("serializes fine"),
200
+ ..Default::default()
201
+ })
202
+ .await;
203
+ Ok(().into())
204
+ },
205
+ );
206
+ worker.register_activity("echo", move |_ctx: ActContext, str: String| async move {
207
+ if shutdown_middle {
208
+ shutdown_barr.wait().await;
209
+ }
210
+ // Take slightly more than two workflow tasks
211
+ tokio::time::sleep(wft_timeout.mul_f32(2.2)).await;
212
+ Ok(str)
213
+ });
214
+ worker
215
+ .submit_wf(
216
+ wf_id.to_owned(),
217
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
218
+ vec![],
219
+ WorkflowOptions::default(),
220
+ )
221
+ .await
222
+ .unwrap();
223
+ let (_, runres) = tokio::join!(
224
+ async {
225
+ if shutdown_middle {
226
+ shutdown_barr.wait().await;
227
+ core.shutdown().await;
228
+ }
229
+ },
230
+ worker.run_until_done()
231
+ );
232
+ runres.unwrap();
233
+ }
234
+
235
+ #[rstest::rstest]
236
+ #[case::retry_then_pass(true)]
237
+ #[case::retry_until_fail(false)]
238
+ #[tokio::test]
239
+ async fn local_act_fail_and_retry(#[case] eventually_pass: bool) {
240
+ let mut t = TestHistoryBuilder::default();
241
+ t.add_by_type(EventType::WorkflowExecutionStarted);
242
+ t.add_workflow_task_scheduled_and_started();
243
+
244
+ let wf_id = "fakeid";
245
+ let mock = mock_workflow_client();
246
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [1], mock);
247
+ let mut worker = mock_sdk(mh);
248
+
249
+ worker.register_wf(
250
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
251
+ move |ctx: WfContext| async move {
252
+ let la_res = ctx
253
+ .local_activity(LocalActivityOptions {
254
+ activity_type: "echo".to_string(),
255
+ input: "hi".as_json_payload().expect("serializes fine"),
256
+ retry_policy: RetryPolicy {
257
+ initial_interval: Some(prost_dur!(from_millis(50))),
258
+ backoff_coefficient: 1.2,
259
+ maximum_interval: None,
260
+ maximum_attempts: 5,
261
+ non_retryable_error_types: vec![],
262
+ },
263
+ ..Default::default()
264
+ })
265
+ .await;
266
+ if eventually_pass {
267
+ assert!(la_res.completed_ok())
268
+ } else {
269
+ assert!(la_res.failed())
270
+ }
271
+ Ok(().into())
272
+ },
273
+ );
274
+ let attempts: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
275
+ worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
276
+ // Succeed on 3rd attempt (which is ==2 since fetch_add returns prev val)
277
+ if 2 == attempts.fetch_add(1, Ordering::Relaxed) && eventually_pass {
278
+ Ok(())
279
+ } else {
280
+ Err(anyhow!("Oh no I failed!"))
281
+ }
282
+ });
283
+ worker
284
+ .submit_wf(
285
+ wf_id.to_owned(),
286
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
287
+ vec![],
288
+ WorkflowOptions::default(),
289
+ )
290
+ .await
291
+ .unwrap();
292
+ worker.run_until_done().await.unwrap();
293
+ let expected_attempts = if eventually_pass { 3 } else { 5 };
294
+ assert_eq!(expected_attempts, attempts.load(Ordering::Relaxed));
295
+ }
296
+
297
+ #[tokio::test]
298
+ async fn local_act_retry_long_backoff_uses_timer() {
299
+ let mut t = TestHistoryBuilder::default();
300
+ t.add_by_type(EventType::WorkflowExecutionStarted);
301
+ t.add_full_wf_task();
302
+ t.add_local_activity_fail_marker(
303
+ 1,
304
+ "1",
305
+ Failure::application_failure("la failed".to_string(), false),
306
+ );
307
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
308
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
309
+ t.add_full_wf_task();
310
+ t.add_local_activity_fail_marker(
311
+ 2,
312
+ "2",
313
+ Failure::application_failure("la failed".to_string(), false),
314
+ );
315
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
316
+ t.add_timer_fired(timer_started_event_id, "2".to_string());
317
+ t.add_full_wf_task();
318
+ t.add_workflow_execution_completed();
319
+
320
+ let wf_id = "fakeid";
321
+ let mock = mock_workflow_client();
322
+ let mh = MockPollCfg::from_resp_batches(
323
+ wf_id,
324
+ t,
325
+ [1.into(), 2.into(), ResponseType::AllHistory],
326
+ mock,
327
+ );
328
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
329
+
330
+ worker.register_wf(
331
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
332
+ |ctx: WfContext| async move {
333
+ let la_res = ctx
334
+ .local_activity(LocalActivityOptions {
335
+ activity_type: "echo".to_string(),
336
+ input: "hi".as_json_payload().expect("serializes fine"),
337
+ retry_policy: RetryPolicy {
338
+ initial_interval: Some(prost_dur!(from_millis(65))),
339
+ // This will make the second backoff 65 seconds, plenty to use timer
340
+ backoff_coefficient: 1_000.,
341
+ maximum_interval: Some(prost_dur!(from_secs(600))),
342
+ maximum_attempts: 3,
343
+ non_retryable_error_types: vec![],
344
+ },
345
+ ..Default::default()
346
+ })
347
+ .await;
348
+ assert!(la_res.failed());
349
+ // Extra timer just to have an extra workflow task which we can return full history for
350
+ ctx.timer(Duration::from_secs(1)).await;
351
+ Ok(().into())
352
+ },
353
+ );
354
+ worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
355
+ Result::<(), _>::Err(anyhow!("Oh no I failed!"))
356
+ });
357
+ worker
358
+ .submit_wf(
359
+ wf_id.to_owned(),
360
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
361
+ vec![],
362
+ WorkflowOptions::default(),
363
+ )
364
+ .await
365
+ .unwrap();
366
+ worker.run_until_done().await.unwrap();
367
+ }
368
+
369
+ #[tokio::test]
370
+ async fn local_act_null_result() {
371
+ let mut t = TestHistoryBuilder::default();
372
+ t.add_by_type(EventType::WorkflowExecutionStarted);
373
+ t.add_full_wf_task();
374
+ t.add_local_activity_marker(1, "1", None, None, |_| {});
375
+ t.add_workflow_execution_completed();
376
+
377
+ let wf_id = "fakeid";
378
+ let mock = mock_workflow_client();
379
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
380
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
381
+
382
+ worker.register_wf(
383
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
384
+ |ctx: WfContext| async move {
385
+ ctx.local_activity(LocalActivityOptions {
386
+ activity_type: "nullres".to_string(),
387
+ input: "hi".as_json_payload().expect("serializes fine"),
388
+ ..Default::default()
389
+ })
390
+ .await;
391
+ Ok(().into())
392
+ },
393
+ );
394
+ worker.register_activity("nullres", |_ctx: ActContext, _: String| async { Ok(()) });
395
+ worker
396
+ .submit_wf(
397
+ wf_id.to_owned(),
398
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
399
+ vec![],
400
+ WorkflowOptions::default(),
401
+ )
402
+ .await
403
+ .unwrap();
404
+ worker.run_until_done().await.unwrap();
405
+ }
406
+
407
+ #[tokio::test]
408
+ async fn local_act_command_immediately_follows_la_marker() {
409
+ // This repro only works both when cache is off, and there is at least one heartbeat wft
410
+ // before the marker & next command are recorded.
411
+ let mut t = TestHistoryBuilder::default();
412
+ t.add_by_type(EventType::WorkflowExecutionStarted);
413
+ t.add_full_wf_task();
414
+ t.add_full_wf_task();
415
+ t.add_local_activity_result_marker(1, "1", "done".into());
416
+ t.add_get_event_id(EventType::TimerStarted, None);
417
+ t.add_full_wf_task();
418
+
419
+ let wf_id = "fakeid";
420
+ let mock = mock_workflow_client();
421
+ // Bug only repros when seeing history up to third wft
422
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [3], mock);
423
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 0);
424
+
425
+ worker.register_wf(
426
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
427
+ |ctx: WfContext| async move {
428
+ ctx.local_activity(LocalActivityOptions {
429
+ activity_type: "nullres".to_string(),
430
+ input: "hi".as_json_payload().expect("serializes fine"),
431
+ ..Default::default()
432
+ })
433
+ .await;
434
+ ctx.timer(Duration::from_secs(1)).await;
435
+ Ok(().into())
436
+ },
437
+ );
438
+ worker.register_activity("nullres", |_ctx: ActContext, _: String| async { Ok(()) });
439
+ worker
440
+ .submit_wf(
441
+ wf_id.to_owned(),
442
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
443
+ vec![],
444
+ WorkflowOptions::default(),
445
+ )
446
+ .await
447
+ .unwrap();
448
+ worker.run_until_done().await.unwrap();
449
+ }
450
+
451
+ #[tokio::test]
452
+ async fn query_during_wft_heartbeat_doesnt_accidentally_fail_to_continue_heartbeat() {
453
+ let wfid = "fake_wf_id";
454
+ let mut t = TestHistoryBuilder::default();
455
+ let mut wes_short_wft_timeout = default_wes_attribs();
456
+ wes_short_wft_timeout.workflow_task_timeout = Some(prost_dur!(from_millis(200)));
457
+ t.add(
458
+ EventType::WorkflowExecutionStarted,
459
+ wes_short_wft_timeout.into(),
460
+ );
461
+ t.add_full_wf_task();
462
+ // get query here
463
+ t.add_full_wf_task();
464
+ t.add_local_activity_result_marker(1, "1", "done".into());
465
+ t.add_workflow_execution_completed();
466
+
467
+ let query_with_hist_task = {
468
+ let mut pr = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1));
469
+ pr.queries = HashMap::new();
470
+ pr.queries.insert(
471
+ "the-query".to_string(),
472
+ WorkflowQuery {
473
+ query_type: "query-type".to_string(),
474
+ query_args: Some(b"hi".into()),
475
+ header: None,
476
+ },
477
+ );
478
+ pr
479
+ };
480
+ let after_la_resolved = Arc::new(Barrier::new(2));
481
+ let poll_barr = after_la_resolved.clone();
482
+ let tasks = [
483
+ query_with_hist_task,
484
+ hist_to_poll_resp(
485
+ &t,
486
+ wfid,
487
+ ResponseType::UntilResolved(
488
+ async move {
489
+ poll_barr.wait().await;
490
+ }
491
+ .boxed(),
492
+ 3,
493
+ ),
494
+ ),
495
+ ];
496
+ let mock = mock_workflow_client();
497
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
498
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
499
+ let core = mock_worker(mock);
500
+
501
+ let barrier = Barrier::new(2);
502
+
503
+ let wf_fut = async {
504
+ let task = core.poll_workflow_activation().await.unwrap();
505
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
506
+ task.run_id,
507
+ schedule_local_activity_cmd(
508
+ 1,
509
+ "act-id",
510
+ ActivityCancellationType::TryCancel,
511
+ Duration::from_secs(60),
512
+ ),
513
+ ))
514
+ .await
515
+ .unwrap();
516
+ let task = core.poll_workflow_activation().await.unwrap();
517
+ // Get query, and complete it
518
+ let query = assert_matches!(
519
+ task.jobs.as_slice(),
520
+ [WorkflowActivationJob {
521
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
522
+ }] => q
523
+ );
524
+ // Now complete the LA
525
+ barrier.wait().await;
526
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
527
+ task.run_id,
528
+ QueryResult {
529
+ query_id: query.query_id.clone(),
530
+ variant: Some(
531
+ QuerySuccess {
532
+ response: Some("whatever".into()),
533
+ }
534
+ .into(),
535
+ ),
536
+ }
537
+ .into(),
538
+ ))
539
+ .await
540
+ .unwrap();
541
+ // Activation with it resolving:
542
+ let task = core.poll_workflow_activation().await.unwrap();
543
+ assert_matches!(
544
+ task.jobs.as_slice(),
545
+ [WorkflowActivationJob {
546
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
547
+ }]
548
+ );
549
+ core.complete_execution(&task.run_id).await;
550
+ };
551
+ let act_fut = async {
552
+ let act_task = core.poll_activity_task().await.unwrap();
553
+ barrier.wait().await;
554
+ core.complete_activity_task(ActivityTaskCompletion {
555
+ task_token: act_task.task_token,
556
+ result: Some(ActivityExecutionResult::ok(vec![1].into())),
557
+ })
558
+ .await
559
+ .unwrap();
560
+ after_la_resolved.wait().await;
561
+ };
562
+
563
+ tokio::join!(wf_fut, act_fut);
564
+ }
565
+
566
+ #[rstest::rstest]
567
+ #[case::impossible_query_in_task(true)]
568
+ #[case::real_history(false)]
569
+ #[tokio::test]
570
+ async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_query_in_task: bool) {
571
+ // Ensures we do not send an activation with a legacy query and any other work, which should
572
+ // never happen, but there was an issue where an LA resolving could trigger that.
573
+ let wfid = "fake_wf_id";
574
+ let mut t = TestHistoryBuilder::default();
575
+ let wes_short_wft_timeout = default_wes_attribs();
576
+ t.add(
577
+ EventType::WorkflowExecutionStarted,
578
+ wes_short_wft_timeout.into(),
579
+ );
580
+ // Since we don't send queries with start workflow, need one workflow task of something else
581
+ // b/c we want to get an activation with a job and a nonlegacy query
582
+ t.add_full_wf_task();
583
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
584
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
585
+
586
+ // nonlegacy query got here & LA started here
587
+ t.add_full_wf_task();
588
+ // legacy query got here, at the same time that the LA is resolved
589
+ t.add_local_activity_result_marker(1, "1", "whatever".into());
590
+ t.add_workflow_execution_completed();
591
+
592
+ let barr = Arc::new(Barrier::new(2));
593
+ let barr_c = barr.clone();
594
+
595
+ let tasks = [
596
+ hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
597
+ {
598
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2));
599
+ pr.queries = HashMap::new();
600
+ pr.queries.insert(
601
+ "q1".to_string(),
602
+ WorkflowQuery {
603
+ query_type: "query-type".to_string(),
604
+ query_args: Some(b"hi".into()),
605
+ header: None,
606
+ },
607
+ );
608
+ pr
609
+ },
610
+ {
611
+ let mut pr = hist_to_poll_resp(
612
+ &t,
613
+ wfid.to_owned(),
614
+ ResponseType::UntilResolved(
615
+ async move {
616
+ barr_c.wait().await;
617
+ // This sleep is the only not-incredibly-invasive way to ensure the LA
618
+ // resolves & updates machines before we process this task
619
+ tokio::time::sleep(Duration::from_secs(1)).await;
620
+ }
621
+ .boxed(),
622
+ 2,
623
+ ),
624
+ );
625
+ // Strip history, we need to look like we hit the cache
626
+ pr.history = Some(History { events: vec![] });
627
+ // In the nonsense server response case, we attach a legacy query, otherwise this
628
+ // response looks like a normal response to a forced WFT heartbeat.
629
+ if impossible_query_in_task {
630
+ pr.query = Some(WorkflowQuery {
631
+ query_type: "query-type".to_string(),
632
+ query_args: Some(b"hi".into()),
633
+ header: None,
634
+ });
635
+ }
636
+ pr
637
+ },
638
+ ];
639
+ let mut mock = mock_workflow_client();
640
+ if impossible_query_in_task {
641
+ mock.expect_respond_legacy_query()
642
+ .times(1)
643
+ .returning(move |_, _| Ok(Default::default()));
644
+ }
645
+ let mut mock = single_hist_mock_sg(wfid, t, tasks, mock, true);
646
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
647
+ let core = mock_worker(mock);
648
+
649
+ let wf_fut = async {
650
+ let task = core.poll_workflow_activation().await.unwrap();
651
+ assert_matches!(
652
+ task.jobs.as_slice(),
653
+ &[WorkflowActivationJob {
654
+ variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
655
+ },]
656
+ );
657
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
658
+ task.run_id,
659
+ start_timer_cmd(1, Duration::from_secs(1)),
660
+ ))
661
+ .await
662
+ .unwrap();
663
+ let task = core.poll_workflow_activation().await.unwrap();
664
+ assert_matches!(
665
+ task.jobs.as_slice(),
666
+ &[
667
+ WorkflowActivationJob {
668
+ variant: Some(workflow_activation_job::Variant::FireTimer(_)),
669
+ },
670
+ WorkflowActivationJob {
671
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(_)),
672
+ }
673
+ ]
674
+ );
675
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
676
+ task.run_id,
677
+ vec![
678
+ schedule_local_activity_cmd(
679
+ 1,
680
+ "act-id",
681
+ ActivityCancellationType::TryCancel,
682
+ Duration::from_secs(60),
683
+ ),
684
+ QueryResult {
685
+ query_id: "q1".to_string(),
686
+ variant: Some(
687
+ QuerySuccess {
688
+ response: Some("whatev".into()),
689
+ }
690
+ .into(),
691
+ ),
692
+ }
693
+ .into(),
694
+ ],
695
+ ))
696
+ .await
697
+ .unwrap();
698
+ barr.wait().await;
699
+ let task = core.poll_workflow_activation().await.unwrap();
700
+ // The next task needs to be resolve, since the LA is completed immediately
701
+ assert_matches!(
702
+ task.jobs.as_slice(),
703
+ [WorkflowActivationJob {
704
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
705
+ }]
706
+ );
707
+ // Complete workflow
708
+ core.complete_execution(&task.run_id).await;
709
+ if impossible_query_in_task {
710
+ // finish last query
711
+ let task = core.poll_workflow_activation().await.unwrap();
712
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
713
+ task.run_id,
714
+ vec![QueryResult {
715
+ query_id: LEGACY_QUERY_ID.to_string(),
716
+ variant: Some(
717
+ QuerySuccess {
718
+ response: Some("whatev".into()),
719
+ }
720
+ .into(),
721
+ ),
722
+ }
723
+ .into()],
724
+ ))
725
+ .await
726
+ .unwrap();
727
+ }
728
+ };
729
+ let act_fut = async {
730
+ let act_task = core.poll_activity_task().await.unwrap();
731
+ core.complete_activity_task(ActivityTaskCompletion {
732
+ task_token: act_task.task_token,
733
+ result: Some(ActivityExecutionResult::ok(vec![1].into())),
734
+ })
735
+ .await
736
+ .unwrap();
737
+ };
738
+
739
+ tokio::join!(wf_fut, act_fut);
740
+ core.shutdown().await;
741
+ }
742
+
743
+ #[tokio::test]
744
+ async fn test_schedule_to_start_timeout() {
745
+ let mut t = TestHistoryBuilder::default();
746
+ t.add_by_type(EventType::WorkflowExecutionStarted);
747
+ t.add_full_wf_task();
748
+
749
+ let wf_id = "fakeid";
750
+ let mock = mock_workflow_client();
751
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::ToTaskNum(1)], mock);
752
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
753
+
754
+ worker.register_wf(
755
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
756
+ |ctx: WfContext| async move {
757
+ let la_res = ctx
758
+ .local_activity(LocalActivityOptions {
759
+ activity_type: "echo".to_string(),
760
+ input: "hi".as_json_payload().expect("serializes fine"),
761
+ // Impossibly small timeout so we timeout in the queue
762
+ schedule_to_start_timeout: prost_dur!(from_nanos(1)),
763
+ ..Default::default()
764
+ })
765
+ .await;
766
+ assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToStart));
767
+ Ok(().into())
768
+ },
769
+ );
770
+ worker.register_activity(
771
+ "echo",
772
+ move |_ctx: ActContext, _: String| async move { Ok(()) },
773
+ );
774
+ worker
775
+ .submit_wf(
776
+ wf_id.to_owned(),
777
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
778
+ vec![],
779
+ WorkflowOptions::default(),
780
+ )
781
+ .await
782
+ .unwrap();
783
+ worker.run_until_done().await.unwrap();
784
+ }
785
+
786
+ #[tokio::test]
787
+ async fn test_schedule_to_start_timeout_not_based_on_original_time() {
788
+ // We used to carry over the schedule time of LAs from the "original" schedule time if these LAs
789
+ // created newly after backing off across a timer. That was a mistake, since schedule-to-start
790
+ // timeouts should apply to when the new attempt was scheduled. This test verifies we don't
791
+ // time out on s-t-s timeouts because of that.
792
+ let mut t = TestHistoryBuilder::default();
793
+ t.add_by_type(EventType::WorkflowExecutionStarted);
794
+ t.add_full_wf_task();
795
+ let orig_sched = SystemTime::now().sub(Duration::from_secs(60 * 20));
796
+ t.add_local_activity_marker(
797
+ 1,
798
+ "1",
799
+ None,
800
+ Some(Failure::application_failure("la failed".to_string(), false)),
801
+ |deets| {
802
+ // Really old schedule time, which should _not_ count against schedule_to_start
803
+ deets.original_schedule_time = Some(orig_sched.into());
804
+ // Backoff value must be present since we're simulating timer backoff
805
+ deets.backoff = Some(prost_dur!(from_secs(100)));
806
+ },
807
+ );
808
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
809
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
810
+ t.add_workflow_task_scheduled_and_started();
811
+
812
+ let wf_id = "fakeid";
813
+ let mock = mock_workflow_client();
814
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
815
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
816
+
817
+ worker.register_wf(
818
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
819
+ |ctx: WfContext| async move {
820
+ let la_res = ctx
821
+ .local_activity(LocalActivityOptions {
822
+ activity_type: "echo".to_string(),
823
+ input: "hi".as_json_payload().expect("serializes fine"),
824
+ retry_policy: RetryPolicy {
825
+ initial_interval: Some(prost_dur!(from_millis(50))),
826
+ backoff_coefficient: 1.2,
827
+ maximum_interval: None,
828
+ maximum_attempts: 5,
829
+ non_retryable_error_types: vec![],
830
+ },
831
+ schedule_to_start_timeout: Some(Duration::from_secs(60)),
832
+ schedule_to_close_timeout: Some(Duration::from_secs(60 * 60)),
833
+ ..Default::default()
834
+ })
835
+ .await;
836
+ assert!(la_res.completed_ok());
837
+ Ok(().into())
838
+ },
839
+ );
840
+ worker.register_activity(
841
+ "echo",
842
+ move |_ctx: ActContext, _: String| async move { Ok(()) },
843
+ );
844
+ worker
845
+ .submit_wf(
846
+ wf_id.to_owned(),
847
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
848
+ vec![],
849
+ WorkflowOptions::default(),
850
+ )
851
+ .await
852
+ .unwrap();
853
+ worker.run_until_done().await.unwrap();
854
+ }
855
+
856
+ #[tokio::test]
857
+ async fn test_schedule_to_close_timeout_based_on_original_time() {
858
+ // We used to carry over the schedule time of LAs from the "original" schedule time if these LAs
859
+ // created newly after backing off across a timer. That was a mistake, since schedule-to-start
860
+ // timeouts should apply to when the new attempt was scheduled. This test verifies we don't
861
+ // time out on s-t-s timeouts because of that.
862
+ let mut t = TestHistoryBuilder::default();
863
+ t.add_by_type(EventType::WorkflowExecutionStarted);
864
+ t.add_full_wf_task();
865
+ let orig_sched = SystemTime::now().sub(Duration::from_secs(60 * 20));
866
+ t.add_local_activity_marker(
867
+ 1,
868
+ "1",
869
+ None,
870
+ Some(Failure::application_failure("la failed".to_string(), false)),
871
+ |deets| {
872
+ // Really old schedule time, which should _not_ count against schedule_to_start
873
+ deets.original_schedule_time = Some(orig_sched.into());
874
+ // Backoff value must be present since we're simulating timer backoff
875
+ deets.backoff = Some(prost_dur!(from_secs(100)));
876
+ },
877
+ );
878
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
879
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
880
+ t.add_workflow_task_scheduled_and_started();
881
+
882
+ let wf_id = "fakeid";
883
+ let mock = mock_workflow_client();
884
+ let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
885
+ let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
886
+
887
+ worker.register_wf(
888
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
889
+ |ctx: WfContext| async move {
890
+ let la_res = ctx
891
+ .local_activity(LocalActivityOptions {
892
+ activity_type: "echo".to_string(),
893
+ input: "hi".as_json_payload().expect("serializes fine"),
894
+ retry_policy: RetryPolicy {
895
+ initial_interval: Some(prost_dur!(from_millis(50))),
896
+ backoff_coefficient: 1.2,
897
+ maximum_interval: None,
898
+ maximum_attempts: 5,
899
+ non_retryable_error_types: vec![],
900
+ },
901
+ // This 10 minute timeout will have already elapsed according to the original
902
+ // schedule time in the history.
903
+ schedule_to_close_timeout: Some(Duration::from_secs(10 * 60)),
904
+ ..Default::default()
905
+ })
906
+ .await;
907
+ assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToClose));
908
+ Ok(().into())
909
+ },
910
+ );
911
+ worker.register_activity(
912
+ "echo",
913
+ move |_ctx: ActContext, _: String| async move { Ok(()) },
914
+ );
915
+ worker
916
+ .submit_wf(
917
+ wf_id.to_owned(),
918
+ DEFAULT_WORKFLOW_TYPE.to_owned(),
919
+ vec![],
920
+ WorkflowOptions::default(),
921
+ )
922
+ .await
923
+ .unwrap();
924
+ worker.run_until_done().await.unwrap();
925
+ }