temporalio 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +20 -0
  4. data/README.md +130 -0
  5. data/bridge/Cargo.lock +2865 -0
  6. data/bridge/Cargo.toml +26 -0
  7. data/bridge/sdk-core/ARCHITECTURE.md +76 -0
  8. data/bridge/sdk-core/Cargo.lock +2606 -0
  9. data/bridge/sdk-core/Cargo.toml +2 -0
  10. data/bridge/sdk-core/LICENSE.txt +23 -0
  11. data/bridge/sdk-core/README.md +107 -0
  12. data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
  13. data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
  14. data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  15. data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
  16. data/bridge/sdk-core/bridge-ffi/Cargo.toml +24 -0
  17. data/bridge/sdk-core/bridge-ffi/LICENSE.txt +23 -0
  18. data/bridge/sdk-core/bridge-ffi/build.rs +25 -0
  19. data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +249 -0
  20. data/bridge/sdk-core/bridge-ffi/src/lib.rs +825 -0
  21. data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +211 -0
  22. data/bridge/sdk-core/client/Cargo.toml +40 -0
  23. data/bridge/sdk-core/client/LICENSE.txt +23 -0
  24. data/bridge/sdk-core/client/src/lib.rs +1294 -0
  25. data/bridge/sdk-core/client/src/metrics.rs +165 -0
  26. data/bridge/sdk-core/client/src/raw.rs +931 -0
  27. data/bridge/sdk-core/client/src/retry.rs +674 -0
  28. data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
  29. data/bridge/sdk-core/core/Cargo.toml +116 -0
  30. data/bridge/sdk-core/core/LICENSE.txt +23 -0
  31. data/bridge/sdk-core/core/benches/workflow_replay.rs +73 -0
  32. data/bridge/sdk-core/core/src/abstractions.rs +166 -0
  33. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +911 -0
  34. data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
  35. data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
  36. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +515 -0
  37. data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
  38. data/bridge/sdk-core/core/src/core_tests/queries.rs +736 -0
  39. data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
  40. data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
  41. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
  42. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2070 -0
  43. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  44. data/bridge/sdk-core/core/src/lib.rs +175 -0
  45. data/bridge/sdk-core/core/src/log_export.rs +62 -0
  46. data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
  47. data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
  48. data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
  49. data/bridge/sdk-core/core/src/replay/mod.rs +71 -0
  50. data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
  51. data/bridge/sdk-core/core/src/telemetry/metrics.rs +383 -0
  52. data/bridge/sdk-core/core/src/telemetry/mod.rs +412 -0
  53. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +77 -0
  54. data/bridge/sdk-core/core/src/test_help/mod.rs +875 -0
  55. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
  56. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1042 -0
  57. data/bridge/sdk-core/core/src/worker/activities.rs +464 -0
  58. data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
  59. data/bridge/sdk-core/core/src/worker/client.rs +347 -0
  60. data/bridge/sdk-core/core/src/worker/mod.rs +566 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +110 -0
  63. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +458 -0
  64. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +911 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +298 -0
  66. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +171 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +860 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +140 -0
  69. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +161 -0
  70. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +133 -0
  71. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1448 -0
  72. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +342 -0
  73. data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +127 -0
  74. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +712 -0
  75. data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +71 -0
  76. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +443 -0
  77. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +439 -0
  78. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +169 -0
  79. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +246 -0
  80. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
  81. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1184 -0
  82. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +277 -0
  83. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  84. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +647 -0
  85. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1143 -0
  86. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
  87. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  88. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +940 -0
  89. data/bridge/sdk-core/core-api/Cargo.toml +31 -0
  90. data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
  91. data/bridge/sdk-core/core-api/src/errors.rs +95 -0
  92. data/bridge/sdk-core/core-api/src/lib.rs +151 -0
  93. data/bridge/sdk-core/core-api/src/worker.rs +135 -0
  94. data/bridge/sdk-core/etc/deps.svg +187 -0
  95. data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
  96. data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
  97. data/bridge/sdk-core/etc/prometheus.yaml +6 -0
  98. data/bridge/sdk-core/fsm/Cargo.toml +18 -0
  99. data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
  100. data/bridge/sdk-core/fsm/README.md +3 -0
  101. data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
  102. data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
  103. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
  104. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
  105. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
  106. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
  107. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
  108. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
  109. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
  110. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
  111. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
  112. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
  113. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
  114. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
  115. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
  116. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
  117. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
  118. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
  119. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
  120. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
  121. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
  122. data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
  123. data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
  124. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
  125. data/bridge/sdk-core/fsm/src/lib.rs +2 -0
  126. data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
  127. data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
  128. data/bridge/sdk-core/integ-with-otel.sh +7 -0
  129. data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
  130. data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
  131. data/bridge/sdk-core/protos/api_upstream/buf.yaml +12 -0
  132. data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
  133. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
  134. data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
  135. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +259 -0
  136. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
  137. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
  138. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
  139. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
  140. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +55 -0
  141. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +168 -0
  142. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +97 -0
  143. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
  144. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
  145. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
  146. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  147. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
  148. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
  149. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
  150. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
  151. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
  152. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
  153. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +751 -0
  154. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
  155. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +161 -0
  156. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +99 -0
  157. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
  158. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
  159. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
  160. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
  161. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
  162. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
  163. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +145 -0
  164. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1124 -0
  165. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +401 -0
  166. data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  167. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  168. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
  169. data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +210 -0
  170. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
  171. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
  172. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
  173. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  174. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +261 -0
  175. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +297 -0
  176. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
  177. data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  178. data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  179. data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  180. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  181. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  182. data/bridge/sdk-core/rustfmt.toml +1 -0
  183. data/bridge/sdk-core/sdk/Cargo.toml +47 -0
  184. data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
  185. data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
  186. data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
  187. data/bridge/sdk-core/sdk/src/conversions.rs +8 -0
  188. data/bridge/sdk-core/sdk/src/interceptors.rs +17 -0
  189. data/bridge/sdk-core/sdk/src/lib.rs +792 -0
  190. data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
  191. data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
  192. data/bridge/sdk-core/sdk/src/workflow_context.rs +683 -0
  193. data/bridge/sdk-core/sdk/src/workflow_future.rs +503 -0
  194. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
  195. data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
  196. data/bridge/sdk-core/sdk-core-protos/build.rs +108 -0
  197. data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  198. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +497 -0
  199. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
  200. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1910 -0
  201. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  202. data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  203. data/bridge/sdk-core/test-utils/Cargo.toml +35 -0
  204. data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
  205. data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
  206. data/bridge/sdk-core/test-utils/src/lib.rs +598 -0
  207. data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
  208. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  209. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +218 -0
  210. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +146 -0
  211. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
  212. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  213. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
  214. data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  215. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
  216. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
  217. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
  218. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
  219. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
  220. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +634 -0
  221. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
  222. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +137 -0
  223. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
  224. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
  225. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
  226. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
  227. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
  228. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +587 -0
  229. data/bridge/sdk-core/tests/load_tests.rs +191 -0
  230. data/bridge/sdk-core/tests/main.rs +111 -0
  231. data/bridge/sdk-core/tests/runner.rs +93 -0
  232. data/bridge/src/connection.rs +167 -0
  233. data/bridge/src/lib.rs +180 -0
  234. data/bridge/src/runtime.rs +47 -0
  235. data/bridge/src/worker.rs +73 -0
  236. data/ext/Rakefile +9 -0
  237. data/lib/bridge.so +0 -0
  238. data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
  239. data/lib/gen/temporal/api/batch/v1/message_pb.rb +48 -0
  240. data/lib/gen/temporal/api/cluster/v1/message_pb.rb +67 -0
  241. data/lib/gen/temporal/api/command/v1/message_pb.rb +166 -0
  242. data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
  243. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +32 -0
  244. data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +26 -0
  245. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +37 -0
  246. data/lib/gen/temporal/api/enums/v1/common_pb.rb +41 -0
  247. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +67 -0
  248. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +71 -0
  249. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
  250. data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
  251. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
  252. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
  253. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
  254. data/lib/gen/temporal/api/enums/v1/update_pb.rb +28 -0
  255. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
  256. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
  257. data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
  258. data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
  259. data/lib/gen/temporal/api/history/v1/message_pb.rb +489 -0
  260. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
  261. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +125 -0
  262. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
  263. data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
  264. data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
  265. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +128 -0
  266. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
  267. data/lib/gen/temporal/api/update/v1/message_pb.rb +26 -0
  268. data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
  269. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +110 -0
  270. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +771 -0
  271. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
  272. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
  273. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
  274. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
  275. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
  276. data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
  277. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
  278. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
  279. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +164 -0
  280. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +192 -0
  281. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
  282. data/lib/temporal/bridge.rb +14 -0
  283. data/lib/temporal/client/implementation.rb +339 -0
  284. data/lib/temporal/client/workflow_handle.rb +243 -0
  285. data/lib/temporal/client.rb +144 -0
  286. data/lib/temporal/connection.rb +736 -0
  287. data/lib/temporal/data_converter.rb +150 -0
  288. data/lib/temporal/error/failure.rb +194 -0
  289. data/lib/temporal/error/workflow_failure.rb +17 -0
  290. data/lib/temporal/errors.rb +22 -0
  291. data/lib/temporal/failure_converter/base.rb +26 -0
  292. data/lib/temporal/failure_converter/basic.rb +313 -0
  293. data/lib/temporal/failure_converter.rb +8 -0
  294. data/lib/temporal/interceptor/chain.rb +27 -0
  295. data/lib/temporal/interceptor/client.rb +102 -0
  296. data/lib/temporal/payload_codec/base.rb +32 -0
  297. data/lib/temporal/payload_converter/base.rb +24 -0
  298. data/lib/temporal/payload_converter/bytes.rb +26 -0
  299. data/lib/temporal/payload_converter/composite.rb +47 -0
  300. data/lib/temporal/payload_converter/encoding_base.rb +35 -0
  301. data/lib/temporal/payload_converter/json.rb +25 -0
  302. data/lib/temporal/payload_converter/nil.rb +25 -0
  303. data/lib/temporal/payload_converter.rb +14 -0
  304. data/lib/temporal/retry_policy.rb +82 -0
  305. data/lib/temporal/retry_state.rb +35 -0
  306. data/lib/temporal/runtime.rb +22 -0
  307. data/lib/temporal/timeout_type.rb +29 -0
  308. data/lib/temporal/version.rb +3 -0
  309. data/lib/temporal/workflow/execution_info.rb +54 -0
  310. data/lib/temporal/workflow/execution_status.rb +36 -0
  311. data/lib/temporal/workflow/id_reuse_policy.rb +36 -0
  312. data/lib/temporal/workflow/query_reject_condition.rb +33 -0
  313. data/lib/temporal.rb +8 -0
  314. data/lib/temporalio.rb +3 -0
  315. data/lib/thermite_patch.rb +23 -0
  316. data/temporalio.gemspec +41 -0
  317. metadata +583 -0
@@ -0,0 +1,712 @@
1
+ //! The patch machine can be difficult to follow. Refer to below table for behavior. The
2
+ //! deprecated calls simply say "allowed" because if they returned a value, it's always true. Old
3
+ //! code cannot exist in workflows which use the deprecated call.
4
+ //!
5
+ //! | History Has | Workflow Has | Outcome |
6
+ //! |------------------------------|-----------------|------------------------------------------------------------------------------------|
7
+ //! | not replaying | no patched | Nothing interesting. Versioning not involved. |
8
+ //! | marker for change | no patched | No matching command / workflow does not support this version |
9
+ //! | deprecated marker for change | no patched | Marker ignored, workflow continues as if it didn't exist |
10
+ //! | replaying, no marker | no patched | Nothing interesting. Versioning not involved. |
11
+ //! | not replaying | patched | Marker command sent to server and recorded. Call returns true |
12
+ //! | marker for change | patched | Call returns true upon replay |
13
+ //! | deprecated marker for change | patched | Call returns true upon replay |
14
+ //! | replaying, no marker | patched | Call returns false upon replay |
15
+ //! | not replaying | deprecate_patch | Marker command sent to server and recorded with deprecated flag. Call allowed |
16
+ //! | marker for change | deprecate_patch | Call allowed |
17
+ //! | deprecated marker for change | deprecate_patch | Call allowed |
18
+ //! | replaying, no marker | deprecate_patch | Call allowed |
19
+
20
+ use super::{
21
+ workflow_machines::MachineResponse, Cancellable, EventInfo, MachineKind, NewMachineWithCommand,
22
+ OnEventWrapper, WFMachinesAdapter, WFMachinesError,
23
+ };
24
+ use crate::protosext::HistoryEventExt;
25
+ use rustfsm::{fsm, TransitionResult};
26
+ use std::convert::TryFrom;
27
+ use temporal_sdk_core_protos::{
28
+ constants::PATCH_MARKER_NAME,
29
+ coresdk::common::build_has_change_marker_details,
30
+ temporal::api::{
31
+ command::v1::{Command, RecordMarkerCommandAttributes},
32
+ enums::v1::CommandType,
33
+ history::v1::HistoryEvent,
34
+ },
35
+ };
36
+
37
+ fsm! {
38
+ pub(super) name PatchMachine;
39
+ command PatchCommand;
40
+ error WFMachinesError;
41
+ shared_state SharedState;
42
+
43
+ // Machine is created in either executing or replaying, and then immediately scheduled and
44
+ // transitions to the command created state (creating the command in the process)
45
+ Executing --(Schedule, on_schedule) --> MarkerCommandCreated;
46
+ Replaying --(Schedule, on_schedule) --> MarkerCommandCreatedReplaying;
47
+
48
+ // Pretty much nothing happens here - once we issue the command it is the responsibility of
49
+ // machinery above us to notify lang SDK about the change. This is in order to allow the
50
+ // change call to be sync and not have to wait for the command to resolve.
51
+ MarkerCommandCreated --(CommandRecordMarker, on_command_record_marker) --> Notified;
52
+ MarkerCommandCreatedReplaying --(CommandRecordMarker) --> Notified;
53
+
54
+ // Once we've played back the marker recorded event, all we need to do is double-check that
55
+ // it matched what we expected
56
+ Notified --(MarkerRecorded(String), shared on_marker_recorded) --> MarkerCommandRecorded;
57
+ }
58
+
59
+ #[derive(Clone)]
60
+ pub(super) struct SharedState {
61
+ patch_id: String,
62
+ }
63
+
64
+ #[derive(Debug, derive_more::Display)]
65
+ pub(super) enum PatchCommand {}
66
+
67
+ /// Patch machines are created when the user invokes `has_change` (or whatever it may be named
68
+ /// in that lang).
69
+ ///
70
+ /// `patch_id`: identifier of a particular change. All calls to get_version that share a change id
71
+ /// are guaranteed to return the same value.
72
+ /// `replaying_when_invoked`: If the workflow is replaying when this invocation occurs, this needs
73
+ /// to be set to true.
74
+ pub(super) fn has_change(
75
+ patch_id: String,
76
+ replaying_when_invoked: bool,
77
+ deprecated: bool,
78
+ ) -> NewMachineWithCommand {
79
+ let (machine, command) =
80
+ PatchMachine::new_scheduled(SharedState { patch_id }, replaying_when_invoked, deprecated);
81
+ NewMachineWithCommand {
82
+ command,
83
+ machine: machine.into(),
84
+ }
85
+ }
86
+
87
+ impl PatchMachine {
88
+ fn new_scheduled(
89
+ state: SharedState,
90
+ replaying_when_invoked: bool,
91
+ deprecated: bool,
92
+ ) -> (Self, Command) {
93
+ let initial_state = if replaying_when_invoked {
94
+ Replaying {}.into()
95
+ } else {
96
+ Executing {}.into()
97
+ };
98
+ let cmd = Command {
99
+ command_type: CommandType::RecordMarker as i32,
100
+ attributes: Some(
101
+ RecordMarkerCommandAttributes {
102
+ marker_name: PATCH_MARKER_NAME.to_string(),
103
+ details: build_has_change_marker_details(&state.patch_id, deprecated),
104
+ header: None,
105
+ failure: None,
106
+ }
107
+ .into(),
108
+ ),
109
+ };
110
+ let mut machine = Self {
111
+ state: initial_state,
112
+ shared_state: state,
113
+ };
114
+ OnEventWrapper::on_event_mut(&mut machine, PatchMachineEvents::Schedule)
115
+ .expect("Patch machine scheduling doesn't fail");
116
+
117
+ (machine, cmd)
118
+ }
119
+ }
120
+
121
+ #[derive(Default, Clone)]
122
+ pub(super) struct Executing {}
123
+
124
+ impl Executing {
125
+ pub(super) fn on_schedule(self) -> PatchMachineTransition<MarkerCommandCreated> {
126
+ TransitionResult::default()
127
+ }
128
+ }
129
+
130
+ #[derive(Default, Clone)]
131
+ pub(super) struct MarkerCommandCreated {}
132
+
133
+ impl MarkerCommandCreated {
134
+ pub(super) fn on_command_record_marker(self) -> PatchMachineTransition<Notified> {
135
+ TransitionResult::commands(vec![])
136
+ }
137
+ }
138
+
139
+ #[derive(Default, Clone)]
140
+ pub(super) struct MarkerCommandCreatedReplaying {}
141
+
142
+ #[derive(Default, Clone)]
143
+ pub(super) struct MarkerCommandRecorded {}
144
+
145
+ #[derive(Default, Clone)]
146
+ pub(super) struct Replaying {}
147
+
148
+ impl Replaying {
149
+ pub(super) fn on_schedule(self) -> PatchMachineTransition<MarkerCommandCreatedReplaying> {
150
+ TransitionResult::default()
151
+ }
152
+ }
153
+
154
+ #[derive(Default, Clone)]
155
+ pub(super) struct Notified {}
156
+ impl From<MarkerCommandCreatedReplaying> for Notified {
157
+ fn from(_: MarkerCommandCreatedReplaying) -> Self {
158
+ Self::default()
159
+ }
160
+ }
161
+ impl Notified {
162
+ pub(super) fn on_marker_recorded(
163
+ self,
164
+ dat: SharedState,
165
+ id: String,
166
+ ) -> PatchMachineTransition<MarkerCommandRecorded> {
167
+ if id != dat.patch_id {
168
+ return TransitionResult::Err(WFMachinesError::Nondeterminism(format!(
169
+ "Change id {} does not match expected id {}",
170
+ id, dat.patch_id
171
+ )));
172
+ }
173
+ TransitionResult::default()
174
+ }
175
+ }
176
+
177
+ impl WFMachinesAdapter for PatchMachine {
178
+ fn adapt_response(
179
+ &self,
180
+ _my_command: Self::Command,
181
+ _event_info: Option<EventInfo>,
182
+ ) -> Result<Vec<MachineResponse>, WFMachinesError> {
183
+ panic!("Patch machine does not produce commands")
184
+ }
185
+
186
+ fn matches_event(&self, event: &HistoryEvent) -> bool {
187
+ event.get_patch_marker_details().is_some()
188
+ }
189
+
190
+ fn kind(&self) -> MachineKind {
191
+ MachineKind::Patch
192
+ }
193
+ }
194
+
195
+ impl Cancellable for PatchMachine {}
196
+
197
+ impl TryFrom<CommandType> for PatchMachineEvents {
198
+ type Error = ();
199
+
200
+ fn try_from(c: CommandType) -> Result<Self, Self::Error> {
201
+ Ok(match c {
202
+ CommandType::RecordMarker => Self::CommandRecordMarker,
203
+ _ => return Err(()),
204
+ })
205
+ }
206
+ }
207
+
208
+ impl TryFrom<HistoryEvent> for PatchMachineEvents {
209
+ type Error = WFMachinesError;
210
+
211
+ fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
212
+ match e.get_patch_marker_details() {
213
+ Some((id, _)) => Ok(Self::MarkerRecorded(id)),
214
+ _ => Err(WFMachinesError::Nondeterminism(format!(
215
+ "Change machine cannot handle this event: {}",
216
+ e
217
+ ))),
218
+ }
219
+ }
220
+ }
221
+
222
+ #[cfg(test)]
223
+ mod tests {
224
+ use crate::{
225
+ replay::TestHistoryBuilder,
226
+ worker::workflow::{machines::WFMachinesError, ManagedWFFunc},
227
+ };
228
+ use rstest::rstest;
229
+ use std::time::Duration;
230
+ use temporal_sdk::{ActivityOptions, WfContext, WorkflowFunction};
231
+ use temporal_sdk_core_protos::{
232
+ constants::PATCH_MARKER_NAME,
233
+ coresdk::{
234
+ common::decode_change_marker_details,
235
+ workflow_activation::{workflow_activation_job, NotifyHasPatch, WorkflowActivationJob},
236
+ },
237
+ temporal::api::{
238
+ command::v1::{
239
+ command::Attributes, RecordMarkerCommandAttributes,
240
+ ScheduleActivityTaskCommandAttributes,
241
+ },
242
+ common::v1::ActivityType,
243
+ enums::v1::{CommandType, EventType},
244
+ history::v1::{
245
+ history_event, ActivityTaskCompletedEventAttributes,
246
+ ActivityTaskScheduledEventAttributes, ActivityTaskStartedEventAttributes,
247
+ TimerFiredEventAttributes,
248
+ },
249
+ },
250
+ };
251
+
252
+ const MY_PATCH_ID: &str = "test_patch_id";
253
+ #[derive(Eq, PartialEq, Copy, Clone)]
254
+ enum MarkerType {
255
+ Deprecated,
256
+ NotDeprecated,
257
+ NoMarker,
258
+ }
259
+
260
+ const ONE_SECOND: Duration = Duration::from_secs(1);
261
+
262
+ /// EVENT_TYPE_WORKFLOW_EXECUTION_STARTED
263
+ /// EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
264
+ /// EVENT_TYPE_WORKFLOW_TASK_STARTED
265
+ /// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
266
+ /// EVENT_TYPE_MARKER_RECORDED (depending on marker_type)
267
+ /// EVENT_TYPE_ACTIVITY_TASK_SCHEDULED
268
+ /// EVENT_TYPE_ACTIVITY_TASK_STARTED
269
+ /// EVENT_TYPE_ACTIVITY_TASK_COMPLETED
270
+ /// EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
271
+ /// EVENT_TYPE_WORKFLOW_TASK_STARTED
272
+ /// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
273
+ /// EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
274
+ fn patch_marker_single_activity(marker_type: MarkerType) -> TestHistoryBuilder {
275
+ let mut t = TestHistoryBuilder::default();
276
+ t.add_by_type(EventType::WorkflowExecutionStarted);
277
+ t.add_full_wf_task();
278
+ match marker_type {
279
+ MarkerType::Deprecated => t.add_has_change_marker(MY_PATCH_ID, true),
280
+ MarkerType::NotDeprecated => t.add_has_change_marker(MY_PATCH_ID, false),
281
+ MarkerType::NoMarker => {}
282
+ };
283
+
284
+ let scheduled_event_id = t.add_get_event_id(
285
+ EventType::ActivityTaskScheduled,
286
+ Some(
287
+ history_event::Attributes::ActivityTaskScheduledEventAttributes(
288
+ ActivityTaskScheduledEventAttributes {
289
+ activity_id: "0".to_string(),
290
+ activity_type: Some(ActivityType {
291
+ name: "".to_string(),
292
+ }),
293
+ ..Default::default()
294
+ },
295
+ ),
296
+ ),
297
+ );
298
+ let started_event_id = t.add_get_event_id(
299
+ EventType::ActivityTaskStarted,
300
+ Some(
301
+ history_event::Attributes::ActivityTaskStartedEventAttributes(
302
+ ActivityTaskStartedEventAttributes {
303
+ scheduled_event_id,
304
+ ..Default::default()
305
+ },
306
+ ),
307
+ ),
308
+ );
309
+ t.add(
310
+ EventType::ActivityTaskCompleted,
311
+ history_event::Attributes::ActivityTaskCompletedEventAttributes(
312
+ ActivityTaskCompletedEventAttributes {
313
+ scheduled_event_id,
314
+ started_event_id,
315
+ ..Default::default()
316
+ },
317
+ ),
318
+ );
319
+ t.add_full_wf_task();
320
+ t.add_workflow_execution_completed();
321
+ t
322
+ }
323
+
324
+ async fn v1(ctx: &mut WfContext) {
325
+ ctx.activity(ActivityOptions {
326
+ activity_id: Some("no_change".to_owned()),
327
+ ..Default::default()
328
+ })
329
+ .await;
330
+ }
331
+
332
+ async fn v2(ctx: &mut WfContext) -> bool {
333
+ if ctx.patched(MY_PATCH_ID) {
334
+ ctx.activity(ActivityOptions {
335
+ activity_id: Some("had_change".to_owned()),
336
+ ..Default::default()
337
+ })
338
+ .await;
339
+ true
340
+ } else {
341
+ ctx.activity(ActivityOptions {
342
+ activity_id: Some("no_change".to_owned()),
343
+ ..Default::default()
344
+ })
345
+ .await;
346
+ false
347
+ }
348
+ }
349
+
350
+ async fn v3(ctx: &mut WfContext) {
351
+ ctx.deprecate_patch(MY_PATCH_ID);
352
+ ctx.activity(ActivityOptions {
353
+ activity_id: Some("had_change".to_owned()),
354
+ ..Default::default()
355
+ })
356
+ .await;
357
+ }
358
+
359
+ async fn v4(ctx: &mut WfContext) {
360
+ ctx.activity(ActivityOptions {
361
+ activity_id: Some("had_change".to_owned()),
362
+ ..Default::default()
363
+ })
364
+ .await;
365
+ }
366
+
367
+ fn patch_setup(
368
+ replaying: bool,
369
+ marker_type: MarkerType,
370
+ workflow_version: usize,
371
+ ) -> ManagedWFFunc {
372
+ let wfn = WorkflowFunction::new(move |mut ctx: WfContext| async move {
373
+ match workflow_version {
374
+ 1 => {
375
+ v1(&mut ctx).await;
376
+ }
377
+ 2 => {
378
+ v2(&mut ctx).await;
379
+ }
380
+ 3 => {
381
+ v3(&mut ctx).await;
382
+ }
383
+ 4 => {
384
+ v4(&mut ctx).await;
385
+ }
386
+ _ => panic!("Invalid workflow version for test setup"),
387
+ }
388
+ Ok(().into())
389
+ });
390
+
391
+ let t = patch_marker_single_activity(marker_type);
392
+ let histinfo = if replaying {
393
+ t.get_full_history_info()
394
+ } else {
395
+ t.get_history_info(1)
396
+ };
397
+ ManagedWFFunc::new_from_update(histinfo.unwrap().into(), wfn, vec![])
398
+ }
399
+
400
+ #[rstest]
401
+ #[case::v1_breaks_on_normal_marker(false, MarkerType::NotDeprecated, 1)]
402
+ #[case::v1_accepts_dep_marker(false, MarkerType::Deprecated, 1)]
403
+ #[case::v1_replay_breaks_on_normal_marker(true, MarkerType::NotDeprecated, 1)]
404
+ #[case::v1_replay_accepts_dep_marker(true, MarkerType::Deprecated, 1)]
405
+ #[case::v4_breaks_on_normal_marker(false, MarkerType::NotDeprecated, 4)]
406
+ #[case::v4_accepts_dep_marker(false, MarkerType::Deprecated, 4)]
407
+ #[case::v4_replay_breaks_on_normal_marker(true, MarkerType::NotDeprecated, 4)]
408
+ #[case::v4_replay_accepts_dep_marker(true, MarkerType::Deprecated, 4)]
409
+ #[tokio::test]
410
+ async fn v1_and_v4_changes(
411
+ #[case] replaying: bool,
412
+ #[case] marker_type: MarkerType,
413
+ #[case] wf_version: usize,
414
+ ) {
415
+ let mut wfm = patch_setup(replaying, marker_type, wf_version);
416
+ // Start workflow activation
417
+ wfm.get_next_activation().await.unwrap();
418
+ let commands = wfm.get_server_commands().commands;
419
+ assert_eq!(commands.len(), 1);
420
+ assert_eq!(
421
+ commands[0].command_type,
422
+ CommandType::ScheduleActivityTask as i32
423
+ );
424
+ let act = if replaying {
425
+ wfm.get_next_activation().await
426
+ } else {
427
+ // Feed more history
428
+ wfm.new_history(
429
+ patch_marker_single_activity(marker_type)
430
+ .get_full_history_info()
431
+ .unwrap()
432
+ .into(),
433
+ )
434
+ .await
435
+ };
436
+
437
+ if marker_type == MarkerType::Deprecated {
438
+ let act = act.unwrap();
439
+ // Activity is resolved
440
+ assert_matches!(
441
+ act.jobs.as_slice(),
442
+ [WorkflowActivationJob {
443
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(_))
444
+ }]
445
+ );
446
+ } else {
447
+ // should explode b/c non-dep marker is present
448
+ assert_matches!(act.unwrap_err(), WFMachinesError::Nondeterminism(_));
449
+ }
450
+
451
+ wfm.shutdown().await.unwrap();
452
+ }
453
+
454
+ #[rstest]
455
+ #[case::v2_no_marker_old_path(false, MarkerType::NoMarker, 2)]
456
+ #[case::v2_marker_new_path(false, MarkerType::NotDeprecated, 2)]
457
+ #[case::v2_dep_marker_new_path(false, MarkerType::Deprecated, 2)]
458
+ #[case::v2_replay_no_marker_old_path(true, MarkerType::NoMarker, 2)]
459
+ #[case::v2_replay_marker_new_path(true, MarkerType::NotDeprecated, 2)]
460
+ #[case::v2_replay_dep_marker_new_path(true, MarkerType::Deprecated, 2)]
461
+ #[case::v3_no_marker_old_path(false, MarkerType::NoMarker, 3)]
462
+ #[case::v3_marker_new_path(false, MarkerType::NotDeprecated, 3)]
463
+ #[case::v3_dep_marker_new_path(false, MarkerType::Deprecated, 3)]
464
+ #[case::v3_replay_no_marker_old_path(true, MarkerType::NoMarker, 3)]
465
+ #[case::v3_replay_marker_new_path(true, MarkerType::NotDeprecated, 3)]
466
+ #[case::v3_replay_dep_marker_new_path(true, MarkerType::Deprecated, 3)]
467
+ #[tokio::test]
468
+ async fn v2_and_v3_changes(
469
+ #[case] replaying: bool,
470
+ #[case] marker_type: MarkerType,
471
+ #[case] wf_version: usize,
472
+ ) {
473
+ let mut wfm = patch_setup(replaying, marker_type, wf_version);
474
+ let act = wfm.get_next_activation().await.unwrap();
475
+ // replaying cases should immediately get a resolve change activation when marker is present
476
+ if replaying && marker_type != MarkerType::NoMarker {
477
+ assert_matches!(
478
+ &act.jobs[1],
479
+ WorkflowActivationJob {
480
+ variant: Some(workflow_activation_job::Variant::NotifyHasPatch(
481
+ NotifyHasPatch {
482
+ patch_id,
483
+ }
484
+ ))
485
+ } => patch_id == MY_PATCH_ID
486
+ );
487
+ } else {
488
+ assert_eq!(act.jobs.len(), 1);
489
+ }
490
+ let commands = wfm.get_server_commands().commands;
491
+ assert_eq!(commands.len(), 2);
492
+ let dep_flag_expected = wf_version != 2;
493
+ assert_matches!(
494
+ commands[0].attributes.as_ref().unwrap(),
495
+ Attributes::RecordMarkerCommandAttributes(
496
+ RecordMarkerCommandAttributes { marker_name, details,.. })
497
+
498
+ if marker_name == PATCH_MARKER_NAME
499
+ && decode_change_marker_details(details).unwrap().1 == dep_flag_expected
500
+ );
501
+ // The only time the "old" timer should fire is in v2, replaying, without a marker.
502
+ let expected_activity_id =
503
+ if replaying && marker_type == MarkerType::NoMarker && wf_version == 2 {
504
+ "no_change"
505
+ } else {
506
+ "had_change"
507
+ };
508
+ assert_matches!(
509
+ commands[1].attributes.as_ref().unwrap(),
510
+ Attributes::ScheduleActivityTaskCommandAttributes(
511
+ ScheduleActivityTaskCommandAttributes { activity_id, .. }
512
+ )
513
+ if activity_id == expected_activity_id
514
+ );
515
+
516
+ let act = if replaying {
517
+ wfm.get_next_activation().await
518
+ } else {
519
+ // Feed more history. Since we are *not* replaying, we *always* "have" the change
520
+ // and the history should have the has-change timer. v3 of course always has the change
521
+ // regardless.
522
+ wfm.new_history(
523
+ patch_marker_single_activity(marker_type)
524
+ .get_full_history_info()
525
+ .unwrap()
526
+ .into(),
527
+ )
528
+ .await
529
+ };
530
+
531
+ let act = act.unwrap();
532
+ // Activity is resolved
533
+ assert_matches!(
534
+ act.jobs.as_slice(),
535
+ [WorkflowActivationJob {
536
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(_))
537
+ }]
538
+ );
539
+
540
+ wfm.shutdown().await.unwrap();
541
+ }
542
+
543
+ #[rstest]
544
+ #[case::has_change_replay(true, true)]
545
+ #[case::no_change_replay(false, true)]
546
+ #[case::has_change_inc(true, false)]
547
+ // The false-false case doesn't make sense, as the incremental cases act as if working against
548
+ // a sticky queue, and it'd be impossible for a worker with the call to get an incremental
549
+ // history that then suddenly doesn't have the marker.
550
+ #[tokio::test]
551
+ async fn same_change_multiple_spots(#[case] have_marker_in_hist: bool, #[case] replay: bool) {
552
+ let wfn = WorkflowFunction::new(move |ctx: WfContext| async move {
553
+ if ctx.patched(MY_PATCH_ID) {
554
+ ctx.activity(ActivityOptions::default()).await;
555
+ } else {
556
+ ctx.timer(ONE_SECOND).await;
557
+ }
558
+ ctx.timer(ONE_SECOND).await;
559
+ if ctx.patched(MY_PATCH_ID) {
560
+ ctx.activity(ActivityOptions::default()).await;
561
+ } else {
562
+ ctx.timer(ONE_SECOND).await;
563
+ }
564
+ Ok(().into())
565
+ });
566
+
567
+ let mut t = TestHistoryBuilder::default();
568
+ t.add_by_type(EventType::WorkflowExecutionStarted);
569
+ t.add_full_wf_task();
570
+ if have_marker_in_hist {
571
+ t.add_has_change_marker(MY_PATCH_ID, false);
572
+ let scheduled_event_id = t.add_get_event_id(
573
+ EventType::ActivityTaskScheduled,
574
+ Some(
575
+ history_event::Attributes::ActivityTaskScheduledEventAttributes(
576
+ ActivityTaskScheduledEventAttributes {
577
+ activity_id: "1".to_owned(),
578
+ activity_type: Some(ActivityType {
579
+ name: "".to_string(),
580
+ }),
581
+ ..Default::default()
582
+ },
583
+ ),
584
+ ),
585
+ );
586
+ let started_event_id = t.add_get_event_id(
587
+ EventType::ActivityTaskStarted,
588
+ Some(
589
+ history_event::Attributes::ActivityTaskStartedEventAttributes(
590
+ ActivityTaskStartedEventAttributes {
591
+ scheduled_event_id,
592
+ ..Default::default()
593
+ },
594
+ ),
595
+ ),
596
+ );
597
+ t.add(
598
+ EventType::ActivityTaskCompleted,
599
+ history_event::Attributes::ActivityTaskCompletedEventAttributes(
600
+ ActivityTaskCompletedEventAttributes {
601
+ scheduled_event_id,
602
+ started_event_id,
603
+ // TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
604
+ ..Default::default()
605
+ },
606
+ ),
607
+ );
608
+ t.add_full_wf_task();
609
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
610
+ t.add(
611
+ EventType::TimerFired,
612
+ history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
613
+ started_event_id: timer_started_event_id,
614
+ timer_id: "1".to_owned(),
615
+ }),
616
+ );
617
+ } else {
618
+ let started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
619
+ t.add(
620
+ EventType::TimerFired,
621
+ history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
622
+ started_event_id,
623
+ timer_id: "1".to_owned(),
624
+ }),
625
+ );
626
+ t.add_full_wf_task();
627
+ let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
628
+ t.add(
629
+ EventType::TimerFired,
630
+ history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
631
+ started_event_id: timer_started_event_id,
632
+ timer_id: "2".to_owned(),
633
+ }),
634
+ );
635
+ }
636
+ t.add_full_wf_task();
637
+
638
+ if have_marker_in_hist {
639
+ let scheduled_event_id = t.add_get_event_id(
640
+ EventType::ActivityTaskScheduled,
641
+ Some(
642
+ history_event::Attributes::ActivityTaskScheduledEventAttributes(
643
+ ActivityTaskScheduledEventAttributes {
644
+ activity_id: "2".to_string(),
645
+ activity_type: Some(ActivityType {
646
+ name: "".to_string(),
647
+ }),
648
+ ..Default::default()
649
+ },
650
+ ),
651
+ ),
652
+ );
653
+ let started_event_id = t.add_get_event_id(
654
+ EventType::ActivityTaskStarted,
655
+ Some(
656
+ history_event::Attributes::ActivityTaskStartedEventAttributes(
657
+ ActivityTaskStartedEventAttributes {
658
+ scheduled_event_id,
659
+ ..Default::default()
660
+ },
661
+ ),
662
+ ),
663
+ );
664
+ t.add(
665
+ EventType::ActivityTaskCompleted,
666
+ history_event::Attributes::ActivityTaskCompletedEventAttributes(
667
+ ActivityTaskCompletedEventAttributes {
668
+ scheduled_event_id,
669
+ started_event_id,
670
+ // TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
671
+ ..Default::default()
672
+ },
673
+ ),
674
+ );
675
+ } else {
676
+ let started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
677
+ t.add(
678
+ EventType::TimerFired,
679
+ history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
680
+ started_event_id,
681
+ timer_id: "3".to_owned(),
682
+ }),
683
+ );
684
+ }
685
+ t.add_full_wf_task();
686
+ t.add_workflow_execution_completed();
687
+
688
+ let mut wfm = if replay {
689
+ let mut wfm = ManagedWFFunc::new_from_update(
690
+ t.get_full_history_info().unwrap().into(),
691
+ wfn,
692
+ vec![],
693
+ );
694
+ // Errors would appear as nondeterminism problems
695
+ wfm.process_all_activations().await.unwrap();
696
+ wfm
697
+ } else {
698
+ let mut wfm =
699
+ ManagedWFFunc::new_from_update(t.get_history_info(1).unwrap().into(), wfn, vec![]);
700
+ wfm.process_all_activations().await.unwrap();
701
+ for i in 2..=4 {
702
+ wfm.new_history(t.get_history_info(i).unwrap().into())
703
+ .await
704
+ .unwrap();
705
+ wfm.process_all_activations().await.unwrap();
706
+ }
707
+ wfm
708
+ };
709
+
710
+ wfm.shutdown().await.unwrap();
711
+ }
712
+ }