temporalio 0.0.1 → 0.1.0

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 (310) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +180 -7
  3. data/bridge/Cargo.lock +208 -76
  4. data/bridge/Cargo.toml +5 -2
  5. data/bridge/sdk-core/Cargo.toml +1 -1
  6. data/bridge/sdk-core/README.md +20 -10
  7. data/bridge/sdk-core/client/Cargo.toml +1 -1
  8. data/bridge/sdk-core/client/src/lib.rs +227 -59
  9. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  10. data/bridge/sdk-core/client/src/raw.rs +13 -12
  11. data/bridge/sdk-core/client/src/retry.rs +132 -43
  12. data/bridge/sdk-core/core/Cargo.toml +28 -15
  13. data/bridge/sdk-core/core/benches/workflow_replay.rs +13 -10
  14. data/bridge/sdk-core/core/src/abstractions.rs +225 -36
  15. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +217 -79
  16. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  17. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +565 -34
  18. data/bridge/sdk-core/core/src/core_tests/queries.rs +247 -90
  19. data/bridge/sdk-core/core/src/core_tests/workers.rs +3 -5
  20. data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
  21. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +430 -67
  22. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  23. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  24. data/bridge/sdk-core/core/src/lib.rs +148 -34
  25. data/bridge/sdk-core/core/src/protosext/mod.rs +1 -1
  26. data/bridge/sdk-core/core/src/replay/mod.rs +185 -41
  27. data/bridge/sdk-core/core/src/telemetry/log_export.rs +190 -0
  28. data/bridge/sdk-core/core/src/telemetry/metrics.rs +219 -140
  29. data/bridge/sdk-core/core/src/telemetry/mod.rs +326 -315
  30. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +20 -14
  31. data/bridge/sdk-core/core/src/test_help/mod.rs +85 -21
  32. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  33. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  34. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +364 -128
  35. data/bridge/sdk-core/core/src/worker/activities.rs +263 -170
  36. data/bridge/sdk-core/core/src/worker/client/mocks.rs +23 -3
  37. data/bridge/sdk-core/core/src/worker/client.rs +48 -6
  38. data/bridge/sdk-core/core/src/worker/mod.rs +186 -75
  39. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  40. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +13 -24
  41. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +879 -226
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +101 -48
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +8 -12
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -9
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +90 -32
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +6 -9
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -10
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +6 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +160 -83
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +36 -54
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +179 -0
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +104 -157
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +8 -12
  54. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -13
  55. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +10 -4
  56. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -11
  57. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  58. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +395 -299
  59. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +12 -20
  60. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +33 -18
  61. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1032 -374
  62. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +525 -392
  63. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  64. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  65. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +3 -6
  66. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  67. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  68. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +456 -681
  69. data/bridge/sdk-core/core-api/Cargo.toml +6 -4
  70. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  71. data/bridge/sdk-core/core-api/src/lib.rs +7 -45
  72. data/bridge/sdk-core/core-api/src/telemetry.rs +141 -0
  73. data/bridge/sdk-core/core-api/src/worker.rs +27 -1
  74. data/bridge/sdk-core/etc/deps.svg +115 -140
  75. data/bridge/sdk-core/etc/regen-depgraph.sh +5 -0
  76. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  77. data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  78. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  79. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  80. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
  81. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
  82. data/bridge/sdk-core/protos/api_upstream/buf.yaml +0 -3
  83. data/bridge/sdk-core/protos/api_upstream/build/go.mod +7 -0
  84. data/bridge/sdk-core/protos/api_upstream/build/go.sum +5 -0
  85. data/bridge/sdk-core/protos/api_upstream/{temporal/api/enums/v1/cluster.proto → build/tools.go} +7 -18
  86. data/bridge/sdk-core/protos/api_upstream/go.mod +6 -0
  87. data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +12 -9
  88. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +15 -26
  89. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  90. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  91. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +4 -9
  92. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  93. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +10 -8
  94. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +28 -2
  95. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  96. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  97. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  98. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  99. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  100. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  101. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  102. data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  103. data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  104. data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  105. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +62 -26
  106. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  107. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +24 -61
  108. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -21
  109. data/bridge/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  110. data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  111. data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  112. data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +110 -31
  113. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  114. data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +4 -4
  115. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  116. data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  117. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +3 -2
  118. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +111 -36
  119. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +19 -5
  120. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  121. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  122. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  123. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  124. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  125. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  126. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +9 -0
  127. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +9 -1
  128. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  129. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  130. data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  131. data/bridge/sdk-core/sdk/Cargo.toml +4 -3
  132. data/bridge/sdk-core/sdk/src/interceptors.rs +36 -3
  133. data/bridge/sdk-core/sdk/src/lib.rs +94 -25
  134. data/bridge/sdk-core/sdk/src/workflow_context.rs +13 -2
  135. data/bridge/sdk-core/sdk/src/workflow_future.rs +10 -13
  136. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  137. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -2
  138. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +164 -104
  139. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +27 -23
  140. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +252 -74
  141. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  142. data/bridge/sdk-core/test-utils/Cargo.toml +4 -1
  143. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  144. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  145. data/bridge/sdk-core/test-utils/src/lib.rs +161 -50
  146. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  147. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  148. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  149. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  150. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  151. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  152. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +239 -0
  153. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -60
  154. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  155. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  156. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  157. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  158. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  159. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  160. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  161. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  162. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +151 -116
  163. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +54 -0
  164. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  165. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +115 -24
  166. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  167. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  168. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  169. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  170. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  171. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +27 -18
  172. data/bridge/sdk-core/tests/main.rs +8 -16
  173. data/bridge/sdk-core/tests/runner.rs +75 -36
  174. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  175. data/bridge/src/connection.rs +117 -82
  176. data/bridge/src/lib.rs +356 -42
  177. data/bridge/src/runtime.rs +10 -3
  178. data/bridge/src/test_server.rs +153 -0
  179. data/bridge/src/worker.rs +133 -9
  180. data/lib/gen/temporal/api/batch/v1/message_pb.rb +8 -6
  181. data/lib/gen/temporal/api/command/v1/message_pb.rb +10 -16
  182. data/lib/gen/temporal/api/common/v1/message_pb.rb +5 -1
  183. data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +2 -1
  184. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +3 -3
  185. data/lib/gen/temporal/api/enums/v1/common_pb.rb +2 -1
  186. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +5 -4
  187. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +9 -1
  188. data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +1 -1
  189. data/lib/gen/temporal/api/enums/v1/query_pb.rb +1 -1
  190. data/lib/gen/temporal/api/enums/v1/reset_pb.rb +1 -1
  191. data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +1 -1
  192. data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +1 -1
  193. data/lib/gen/temporal/api/enums/v1/update_pb.rb +7 -10
  194. data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +1 -1
  195. data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +1 -1
  196. data/lib/gen/temporal/api/failure/v1/message_pb.rb +1 -1
  197. data/lib/gen/temporal/api/filter/v1/message_pb.rb +1 -1
  198. data/lib/gen/temporal/api/history/v1/message_pb.rb +34 -25
  199. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +2 -1
  200. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +14 -51
  201. data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +1 -1
  202. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  203. data/lib/gen/temporal/api/query/v1/message_pb.rb +1 -1
  204. data/lib/gen/temporal/api/replication/v1/message_pb.rb +1 -1
  205. data/lib/gen/temporal/api/schedule/v1/message_pb.rb +22 -1
  206. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  207. data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +2 -2
  208. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  209. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  210. data/lib/gen/temporal/api/update/v1/message_pb.rb +49 -3
  211. data/lib/gen/temporal/api/version/v1/message_pb.rb +1 -1
  212. data/lib/gen/temporal/api/workflow/v1/message_pb.rb +2 -1
  213. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +47 -20
  214. data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +1 -1
  215. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  216. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  217. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  218. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  219. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  220. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  221. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +28 -21
  222. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +32 -24
  223. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  224. data/lib/temporalio/activity/context.rb +102 -0
  225. data/lib/temporalio/activity/info.rb +67 -0
  226. data/lib/temporalio/activity.rb +85 -0
  227. data/lib/temporalio/bridge/connect_options.rb +15 -0
  228. data/lib/temporalio/bridge/error.rb +8 -0
  229. data/lib/temporalio/bridge/retry_config.rb +24 -0
  230. data/lib/temporalio/bridge/tls_options.rb +19 -0
  231. data/lib/temporalio/bridge.rb +14 -0
  232. data/lib/{temporal → temporalio}/client/implementation.rb +57 -56
  233. data/lib/{temporal → temporalio}/client/workflow_handle.rb +35 -35
  234. data/lib/{temporal → temporalio}/client.rb +19 -32
  235. data/lib/temporalio/connection/retry_config.rb +44 -0
  236. data/lib/temporalio/connection/service.rb +20 -0
  237. data/lib/temporalio/connection/test_service.rb +92 -0
  238. data/lib/temporalio/connection/tls_options.rb +51 -0
  239. data/lib/temporalio/connection/workflow_service.rb +731 -0
  240. data/lib/temporalio/connection.rb +86 -0
  241. data/lib/{temporal → temporalio}/data_converter.rb +76 -35
  242. data/lib/{temporal → temporalio}/error/failure.rb +6 -6
  243. data/lib/{temporal → temporalio}/error/workflow_failure.rb +4 -2
  244. data/lib/{temporal → temporalio}/errors.rb +19 -1
  245. data/lib/{temporal → temporalio}/failure_converter/base.rb +5 -5
  246. data/lib/{temporal → temporalio}/failure_converter/basic.rb +58 -52
  247. data/lib/temporalio/failure_converter.rb +7 -0
  248. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  249. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  250. data/lib/{temporal → temporalio}/interceptor/chain.rb +7 -6
  251. data/lib/{temporal → temporalio}/interceptor/client.rb +27 -2
  252. data/lib/temporalio/interceptor.rb +22 -0
  253. data/lib/{temporal → temporalio}/payload_codec/base.rb +5 -5
  254. data/lib/{temporal → temporalio}/payload_converter/base.rb +3 -3
  255. data/lib/{temporal → temporalio}/payload_converter/bytes.rb +4 -3
  256. data/lib/{temporal → temporalio}/payload_converter/composite.rb +7 -5
  257. data/lib/{temporal → temporalio}/payload_converter/encoding_base.rb +4 -4
  258. data/lib/{temporal → temporalio}/payload_converter/json.rb +4 -3
  259. data/lib/{temporal → temporalio}/payload_converter/nil.rb +4 -3
  260. data/lib/temporalio/payload_converter.rb +14 -0
  261. data/lib/{temporal → temporalio}/retry_policy.rb +17 -7
  262. data/lib/{temporal → temporalio}/retry_state.rb +1 -1
  263. data/lib/temporalio/runtime.rb +25 -0
  264. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  265. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  266. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  267. data/lib/temporalio/testing.rb +175 -0
  268. data/lib/{temporal → temporalio}/timeout_type.rb +2 -2
  269. data/lib/temporalio/version.rb +3 -0
  270. data/lib/temporalio/worker/activity_runner.rb +114 -0
  271. data/lib/temporalio/worker/activity_worker.rb +164 -0
  272. data/lib/temporalio/worker/reactor.rb +46 -0
  273. data/lib/temporalio/worker/runner.rb +63 -0
  274. data/lib/temporalio/worker/sync_worker.rb +124 -0
  275. data/lib/temporalio/worker/thread_pool_executor.rb +51 -0
  276. data/lib/temporalio/worker.rb +204 -0
  277. data/lib/temporalio/workflow/async.rb +46 -0
  278. data/lib/{temporal → temporalio}/workflow/execution_info.rb +4 -4
  279. data/lib/{temporal → temporalio}/workflow/execution_status.rb +1 -1
  280. data/lib/temporalio/workflow/future.rb +138 -0
  281. data/lib/{temporal → temporalio}/workflow/id_reuse_policy.rb +6 -6
  282. data/lib/temporalio/workflow/info.rb +76 -0
  283. data/lib/{temporal → temporalio}/workflow/query_reject_condition.rb +5 -5
  284. data/lib/temporalio.rb +12 -3
  285. data/temporalio.gemspec +11 -6
  286. metadata +137 -64
  287. data/bridge/sdk-core/Cargo.lock +0 -2606
  288. data/bridge/sdk-core/bridge-ffi/Cargo.toml +0 -24
  289. data/bridge/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  290. data/bridge/sdk-core/bridge-ffi/build.rs +0 -25
  291. data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -249
  292. data/bridge/sdk-core/bridge-ffi/src/lib.rs +0 -825
  293. data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +0 -211
  294. data/bridge/sdk-core/core/src/log_export.rs +0 -62
  295. data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
  296. data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
  297. data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
  298. data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  299. data/bridge/sdk-core/sdk/src/conversions.rs +0 -8
  300. data/lib/bridge.so +0 -0
  301. data/lib/gen/temporal/api/cluster/v1/message_pb.rb +0 -67
  302. data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +0 -26
  303. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
  304. data/lib/temporal/bridge.rb +0 -14
  305. data/lib/temporal/connection.rb +0 -736
  306. data/lib/temporal/failure_converter.rb +0 -8
  307. data/lib/temporal/payload_converter.rb +0 -14
  308. data/lib/temporal/runtime.rb +0 -22
  309. data/lib/temporal/version.rb +0 -3
  310. data/lib/temporal.rb +0 -8
@@ -23,6 +23,6 @@ async fn main() -> Result<(), anyhow::Error> {
23
23
  .expect("history field must be populated");
24
24
  // Serialize history to file
25
25
  let byteified = hist.encode_to_vec();
26
- tokio::fs::write(format!("{}_history.bin", wf_id), &byteified).await?;
26
+ tokio::fs::write(format!("{wf_id}_history.bin"), &byteified).await?;
27
27
  Ok(())
28
28
  }
@@ -5,8 +5,14 @@
5
5
  extern crate tracing;
6
6
 
7
7
  pub mod canned_histories;
8
+ pub mod wf_input_saver;
9
+ pub mod workflows;
8
10
 
9
- use crate::stream::TryStreamExt;
11
+ use crate::{
12
+ stream::{Stream, TryStreamExt},
13
+ wf_input_saver::stream_to_file,
14
+ };
15
+ use base64::{prelude::BASE64_STANDARD, Engine};
10
16
  use futures::{future, stream, stream::FuturesUnordered, StreamExt};
11
17
  use parking_lot::Mutex;
12
18
  use prost::Message;
@@ -18,14 +24,24 @@ use std::{
18
24
  use temporal_client::{
19
25
  Client, RetryClient, WorkflowClientTrait, WorkflowExecutionInfo, WorkflowOptions,
20
26
  };
21
- use temporal_sdk::{interceptors::WorkerInterceptor, IntoActivityFunc, Worker, WorkflowFunction};
27
+ use temporal_sdk::{
28
+ interceptors::{FailOnNondeterminismInterceptor, WorkerInterceptor},
29
+ IntoActivityFunc, Worker, WorkflowFunction,
30
+ };
22
31
  use temporal_sdk_core::{
23
32
  ephemeral_server::{EphemeralExe, EphemeralExeVersion},
24
- init_replay_worker, init_worker, telemetry_init, ClientOptions, ClientOptionsBuilder, Logger,
25
- MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
26
- TraceExporter, WorkerConfig, WorkerConfigBuilder,
33
+ init_replay_worker, init_worker,
34
+ replay::HistoryForReplay,
35
+ ClientOptions, ClientOptionsBuilder, CoreRuntime, WorkerConfig, WorkerConfigBuilder,
36
+ };
37
+ use temporal_sdk_core_api::errors::{PollActivityError, PollWfError};
38
+ use temporal_sdk_core_api::{
39
+ telemetry::{
40
+ Logger, MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
41
+ TraceExportConfig, TraceExporter,
42
+ },
43
+ Worker as CoreWorker,
27
44
  };
28
- use temporal_sdk_core_api::Worker as CoreWorker;
29
45
  use temporal_sdk_core_protos::{
30
46
  coresdk::{
31
47
  workflow_commands::{
@@ -35,16 +51,17 @@ use temporal_sdk_core_protos::{
35
51
  workflow_completion::WorkflowActivationCompletion,
36
52
  },
37
53
  temporal::api::{common::v1::Payload, history::v1::History},
54
+ DEFAULT_ACTIVITY_TYPE,
38
55
  };
39
- use tokio::sync::OnceCell;
56
+ use tokio::sync::{mpsc::unbounded_channel, OnceCell};
40
57
  use url::Url;
41
58
 
42
59
  pub const NAMESPACE: &str = "default";
43
60
  pub const TEST_Q: &str = "q";
44
61
  /// The env var used to specify where the integ tests should point
45
62
  pub const INTEG_SERVER_TARGET_ENV_VAR: &str = "TEMPORAL_SERVICE_ADDRESS";
46
- /// This env var is set (to any value) if temporalite is in use
47
- pub const INTEG_TEMPORALITE_USED_ENV_VAR: &str = "INTEG_TEMPORALITE_ON";
63
+ /// This env var is set (to any value) if temporal CLI dev server is in use
64
+ pub const INTEG_TEMPORAL_DEV_SERVER_USED_ENV_VAR: &str = "INTEG_TEMPORAL_DEV_SERVER_ON";
48
65
  /// This env var is set (to any value) if the test server is in use
49
66
  pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
50
67
 
@@ -52,6 +69,15 @@ pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
52
69
  const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
53
70
  /// If set, enable direct scraping of prom metrics on the specified port
54
71
  const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
72
+ #[macro_export]
73
+ macro_rules! prost_dur {
74
+ ($dur_call:ident $args:tt) => {
75
+ std::time::Duration::$dur_call$args
76
+ .try_into()
77
+ .expect("test duration fits")
78
+ };
79
+ }
80
+
55
81
  /// Create a worker instance which will use the provided test name to base the task queue and wf id
56
82
  /// upon. Returns the instance and the task queue name (which is also the workflow id).
57
83
  pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
@@ -61,21 +87,44 @@ pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
61
87
  starter
62
88
  }
63
89
 
64
- /// Create a worker replay instance preloaded with a provided history. Returns the worker impl
65
- /// and the task queue name as in [init_core_and_create_wf].
66
- pub fn init_core_replay_preloaded(
67
- test_name: &str,
68
- history: &History,
69
- ) -> (Arc<dyn CoreWorker>, String) {
70
- telemetry_init(&get_integ_telem_options()).expect("Telemetry inits cleanly");
90
+ /// Create a worker replay instance preloaded with provided histories. Returns the worker impl.
91
+ pub fn init_core_replay_preloaded<I>(test_name: &str, histories: I) -> Arc<dyn CoreWorker>
92
+ where
93
+ I: IntoIterator<Item = HistoryForReplay> + 'static,
94
+ <I as IntoIterator>::IntoIter: Send,
95
+ {
96
+ init_core_replay_stream(test_name, stream::iter(histories))
97
+ }
98
+ pub fn init_core_replay_stream<I>(test_name: &str, histories: I) -> Arc<dyn CoreWorker>
99
+ where
100
+ I: Stream<Item = HistoryForReplay> + Send + 'static,
101
+ {
102
+ init_integ_telem();
71
103
  let worker_cfg = WorkerConfigBuilder::default()
72
104
  .namespace(NAMESPACE)
73
105
  .task_queue(test_name)
74
106
  .worker_build_id("test_bin_id")
75
107
  .build()
76
108
  .expect("Configuration options construct properly");
77
- let worker = init_replay_worker(worker_cfg, history).expect("Replay worker must init properly");
78
- (Arc::new(worker), test_name.to_string())
109
+ let worker =
110
+ init_replay_worker(worker_cfg, histories).expect("Replay worker must init properly");
111
+ Arc::new(worker)
112
+ }
113
+ pub fn replay_sdk_worker<I>(histories: I) -> Worker
114
+ where
115
+ I: IntoIterator<Item = HistoryForReplay> + 'static,
116
+ <I as IntoIterator>::IntoIter: Send,
117
+ {
118
+ replay_sdk_worker_stream(stream::iter(histories))
119
+ }
120
+ pub fn replay_sdk_worker_stream<I>(histories: I) -> Worker
121
+ where
122
+ I: Stream<Item = HistoryForReplay> + Send + 'static,
123
+ {
124
+ let core = init_core_replay_stream("replay_worker_test", histories);
125
+ let mut worker = Worker::new_from_core(core, "replay_q".to_string());
126
+ worker.set_worker_interceptor(Box::new(FailOnNondeterminismInterceptor {}));
127
+ worker
79
128
  }
80
129
 
81
130
  /// Load history from a file containing the protobuf serialization of it
@@ -87,13 +136,24 @@ pub async fn history_from_proto_binary(path_from_root: &str) -> Result<History,
87
136
  Ok(History::decode(&*bytes)?)
88
137
  }
89
138
 
139
+ static INTEG_TESTS_RT: once_cell::sync::OnceCell<CoreRuntime> = once_cell::sync::OnceCell::new();
140
+ pub fn init_integ_telem() {
141
+ INTEG_TESTS_RT.get_or_init(|| {
142
+ let telemetry_options = get_integ_telem_options();
143
+ let rt =
144
+ CoreRuntime::new_assume_tokio(telemetry_options).expect("Core runtime inits cleanly");
145
+ let _ = tracing::subscriber::set_global_default(rt.trace_subscriber());
146
+ rt
147
+ });
148
+ }
149
+
90
150
  /// Implements a builder pattern to help integ tests initialize core and create workflows
91
151
  pub struct CoreWfStarter {
92
152
  /// Used for both the task queue and workflow id
93
153
  task_queue_name: String,
94
- telemetry_options: TelemetryOptions,
95
154
  pub worker_config: WorkerConfig,
96
- wft_timeout: Option<Duration>,
155
+ /// Options to use when starting workflow(s)
156
+ pub workflow_options: WorkflowOptions,
97
157
  initted_worker: OnceCell<InitializedWorker>,
98
158
  }
99
159
  struct InitializedWorker {
@@ -103,16 +163,12 @@ struct InitializedWorker {
103
163
 
104
164
  impl CoreWfStarter {
105
165
  pub fn new(test_name: &str) -> Self {
166
+ init_integ_telem();
106
167
  let rand_bytes: Vec<u8> = rand::thread_rng().sample_iter(&Standard).take(6).collect();
107
- let task_q_salt = base64::encode(rand_bytes);
108
- let task_queue = format!("{}_{}", test_name, task_q_salt);
109
- Self::new_tq_name(&task_queue)
110
- }
111
-
112
- pub fn new_tq_name(task_queue: &str) -> Self {
168
+ let task_q_salt = BASE64_STANDARD.encode(rand_bytes);
169
+ let task_queue = format!("{test_name}_{task_q_salt}");
113
170
  Self {
114
171
  task_queue_name: task_queue.to_owned(),
115
- telemetry_options: get_integ_telem_options(),
116
172
  worker_config: WorkerConfigBuilder::default()
117
173
  .namespace(NAMESPACE)
118
174
  .task_queue(task_queue)
@@ -120,8 +176,8 @@ impl CoreWfStarter {
120
176
  .max_cached_workflows(1000_usize)
121
177
  .build()
122
178
  .unwrap(),
123
- wft_timeout: None,
124
179
  initted_worker: OnceCell::new(),
180
+ workflow_options: Default::default(),
125
181
  }
126
182
  }
127
183
 
@@ -148,13 +204,27 @@ impl CoreWfStarter {
148
204
  }
149
205
 
150
206
  /// Start the workflow defined by the builder and return run id
151
- pub async fn start_wf(&self) -> String {
152
- self.start_wf_with_id(self.task_queue_name.clone(), WorkflowOptions::default())
207
+ pub async fn start_wf(&mut self) -> String {
208
+ self.start_wf_with_id(self.task_queue_name.clone()).await
209
+ }
210
+
211
+ pub async fn start_with_worker(
212
+ &self,
213
+ wf_name: impl Into<String>,
214
+ worker: &mut TestWorker,
215
+ ) -> String {
216
+ worker
217
+ .submit_wf(
218
+ self.task_queue_name.clone(),
219
+ wf_name.into(),
220
+ vec![],
221
+ self.workflow_options.clone(),
222
+ )
153
223
  .await
224
+ .unwrap()
154
225
  }
155
226
 
156
- pub async fn start_wf_with_id(&self, workflow_id: String, mut opts: WorkflowOptions) -> String {
157
- opts.task_timeout = opts.task_timeout.or(self.wft_timeout);
227
+ pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
158
228
  self.initted_worker
159
229
  .get()
160
230
  .expect(
@@ -168,7 +238,7 @@ impl CoreWfStarter {
168
238
  workflow_id,
169
239
  self.task_queue_name.clone(),
170
240
  None,
171
- opts,
241
+ self.workflow_options.clone(),
172
242
  )
173
243
  .await
174
244
  .unwrap()
@@ -181,19 +251,21 @@ impl CoreWfStarter {
181
251
  &mut self,
182
252
  wf_id: impl Into<String>,
183
253
  run_id: impl Into<String>,
184
- // TODO: Need not be passed in
185
254
  worker: &mut Worker,
186
255
  ) -> Result<(), anyhow::Error> {
256
+ let wf_id = wf_id.into();
187
257
  // Fetch history and replay it
188
258
  let history = self
189
259
  .get_client()
190
260
  .await
191
- .get_workflow_execution_history(wf_id.into(), Some(run_id.into()), vec![])
261
+ .get_workflow_execution_history(wf_id.clone(), Some(run_id.into()), vec![])
192
262
  .await?
193
263
  .history
194
264
  .expect("history field must be populated");
195
- let (replay_worker, _) = init_core_replay_preloaded(worker.task_queue(), &history);
265
+ let with_id = HistoryForReplay::new(history, wf_id);
266
+ let replay_worker = init_core_replay_preloaded(worker.task_queue(), [with_id]);
196
267
  worker.with_new_core_worker(replay_worker);
268
+ worker.set_worker_interceptor(Box::new(FailOnNondeterminismInterceptor {}));
197
269
  worker.run().await.unwrap();
198
270
  Ok(())
199
271
  }
@@ -231,22 +303,36 @@ impl CoreWfStarter {
231
303
  self
232
304
  }
233
305
 
234
- pub fn wft_timeout(&mut self, timeout: Duration) -> &mut Self {
235
- self.wft_timeout = Some(timeout);
306
+ pub fn no_remote_activities(&mut self) -> &mut Self {
307
+ self.worker_config.no_remote_activities = true;
308
+ self
309
+ }
310
+
311
+ pub fn enable_wf_state_input_recording(&mut self) -> &mut Self {
312
+ let (ser_tx, ser_rx) = unbounded_channel();
313
+ let worker_cfg_clone = self.worker_config.clone();
314
+ tokio::spawn(async move {
315
+ stream_to_file(&worker_cfg_clone, ser_rx).await.unwrap();
316
+ });
317
+ self.worker_config.wf_state_inputs = Some(ser_tx);
236
318
  self
237
319
  }
238
320
 
239
321
  async fn get_or_init(&mut self) -> &InitializedWorker {
240
322
  self.initted_worker
241
323
  .get_or_init(|| async {
242
- telemetry_init(&self.telemetry_options).expect("Telemetry inits cleanly");
243
324
  let client = Arc::new(
244
325
  get_integ_server_options()
245
326
  .connect(self.worker_config.namespace.clone(), None, None)
246
327
  .await
247
328
  .expect("Must connect"),
248
329
  );
249
- let worker = init_worker(self.worker_config.clone(), client.clone());
330
+ let worker = init_worker(
331
+ INTEG_TESTS_RT.get().unwrap(),
332
+ self.worker_config.clone(),
333
+ client.clone(),
334
+ )
335
+ .expect("Worker inits cleanly");
250
336
  InitializedWorker {
251
337
  worker: Arc::new(worker),
252
338
  client,
@@ -442,7 +528,6 @@ impl WorkerInterceptor for TestWorkerCompletionIceptor {
442
528
 
443
529
  /// Returns the client options used to connect to the server used for integration tests.
444
530
  pub fn get_integ_server_options() -> ClientOptions {
445
- telemetry_init(&get_integ_telem_options()).expect("Telemetry inits cleanly");
446
531
  let temporal_server_address = match env::var(INTEG_SERVER_TARGET_ENV_VAR) {
447
532
  Ok(addr) => addr,
448
533
  Err(_) => "http://localhost:7233".to_owned(),
@@ -459,6 +544,8 @@ pub fn get_integ_server_options() -> ClientOptions {
459
544
 
460
545
  pub fn get_integ_telem_options() -> TelemetryOptions {
461
546
  let mut ob = TelemetryOptionsBuilder::default();
547
+ let filter_string =
548
+ env::var("RUST_LOG").unwrap_or_else(|_| "temporal_sdk_core=INFO".to_string());
462
549
  if let Some(url) = env::var(OTEL_URL_ENV_VAR)
463
550
  .ok()
464
551
  .map(|x| x.parse::<Url>().unwrap())
@@ -466,8 +553,12 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
466
553
  let opts = OtelCollectorOptions {
467
554
  url,
468
555
  headers: Default::default(),
556
+ metric_periodicity: None,
469
557
  };
470
- ob.tracing(TraceExporter::Otel(opts.clone()));
558
+ ob.tracing(TraceExportConfig {
559
+ filter: filter_string.clone(),
560
+ exporter: TraceExporter::Otel(opts.clone()),
561
+ });
471
562
  ob.metrics(MetricsExporter::Otel(opts));
472
563
  }
473
564
  if let Some(addr) = env::var(PROM_ENABLE_ENV_VAR)
@@ -476,15 +567,16 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
476
567
  {
477
568
  ob.metrics(MetricsExporter::Prometheus(addr));
478
569
  }
479
- ob.tracing_filter(env::var("RUST_LOG").unwrap_or_else(|_| "temporal_sdk_core=INFO".to_string()))
480
- .logging(Logger::Console)
481
- .build()
482
- .unwrap()
570
+ ob.logging(Logger::Console {
571
+ filter: filter_string,
572
+ })
573
+ .build()
574
+ .unwrap()
483
575
  }
484
576
 
485
577
  pub fn default_cached_download() -> EphemeralExe {
486
578
  EphemeralExe::CachedDownload {
487
- version: EphemeralExeVersion::Default {
579
+ version: EphemeralExeVersion::SDKDefault {
488
580
  sdk_name: "sdk-rust".to_string(),
489
581
  sdk_version: "0.1.0".to_string(),
490
582
  },
@@ -503,8 +595,7 @@ pub fn schedule_activity_cmd(
503
595
  ScheduleActivity {
504
596
  seq,
505
597
  activity_id: activity_id.to_string(),
506
- activity_type: "test_activity".to_string(),
507
- namespace: NAMESPACE.to_owned(),
598
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
508
599
  task_queue: task_q.to_owned(),
509
600
  schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
510
601
  start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
@@ -525,7 +616,7 @@ pub fn schedule_local_activity_cmd(
525
616
  ScheduleLocalActivity {
526
617
  seq,
527
618
  activity_id: activity_id.to_string(),
528
- activity_type: "test_activity".to_string(),
619
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
529
620
  schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
530
621
  start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
531
622
  schedule_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
@@ -596,3 +687,23 @@ where
596
687
  .unwrap();
597
688
  }
598
689
  }
690
+
691
+ /// Initiate shutdown, drain the pollers, and wait for shutdown to complete.
692
+ pub async fn drain_pollers_and_shutdown(worker: &Arc<dyn CoreWorker>) {
693
+ worker.initiate_shutdown();
694
+ tokio::join!(
695
+ async {
696
+ assert!(matches!(
697
+ worker.poll_activity_task().await.unwrap_err(),
698
+ PollActivityError::ShutDown
699
+ ));
700
+ },
701
+ async {
702
+ assert!(matches!(
703
+ worker.poll_workflow_activation().await.unwrap_err(),
704
+ PollWfError::ShutDown,
705
+ ));
706
+ }
707
+ );
708
+ worker.shutdown().await;
709
+ }
@@ -0,0 +1,50 @@
1
+ use anyhow::anyhow;
2
+ use bytes::BytesMut;
3
+ use futures::{stream::BoxStream, SinkExt, StreamExt};
4
+ use prost::bytes::Bytes;
5
+ use std::path::Path;
6
+ use temporal_sdk_core_api::worker::WorkerConfig;
7
+ use tokio::{fs::File, sync::mpsc::UnboundedReceiver};
8
+ use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
9
+
10
+ pub struct WFStateReplayData {
11
+ pub config: WorkerConfig,
12
+ pub inputs: BoxStream<'static, Result<BytesMut, std::io::Error>>,
13
+ }
14
+
15
+ pub async fn stream_to_file(
16
+ config: &WorkerConfig,
17
+ mut rcv: UnboundedReceiver<Vec<u8>>,
18
+ ) -> Result<(), anyhow::Error> {
19
+ let file = File::create("wf_inputs").await?;
20
+ let mut transport = FramedWrite::new(file, ldc());
21
+ // First write the worker config, since things like cache size affect how many evictions there
22
+ // will be, etc.
23
+ transport.send(rmp_serde::to_vec(config)?.into()).await?;
24
+ while let Some(v) = rcv.recv().await {
25
+ transport.send(Bytes::from(v)).await?;
26
+ }
27
+ Ok(())
28
+ }
29
+
30
+ pub async fn read_from_file(path: impl AsRef<Path>) -> Result<WFStateReplayData, anyhow::Error> {
31
+ let file = File::open(path).await?;
32
+ let mut framed_read = FramedRead::new(file, ldc());
33
+ // Deserialize the worker config first
34
+ let config = framed_read
35
+ .next()
36
+ .await
37
+ .ok_or_else(|| anyhow!("Replay data file is empty"))??;
38
+ let config = rmp_serde::from_slice(config.as_ref())?;
39
+
40
+ Ok(WFStateReplayData {
41
+ config,
42
+ inputs: framed_read.boxed(),
43
+ })
44
+ }
45
+
46
+ fn ldc() -> LengthDelimitedCodec {
47
+ LengthDelimitedCodec::builder()
48
+ .length_field_type::<u16>()
49
+ .new_codec()
50
+ }
@@ -0,0 +1,29 @@
1
+ use crate::prost_dur;
2
+ use std::time::Duration;
3
+ use temporal_sdk::{ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
4
+ use temporal_sdk_core_protos::{coresdk::AsJsonPayloadExt, temporal::api::common::v1::RetryPolicy};
5
+
6
+ pub async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
7
+ ctx.local_activity(LocalActivityOptions {
8
+ activity_type: "delay".to_string(),
9
+ input: "hi".as_json_payload().expect("serializes fine"),
10
+ retry_policy: RetryPolicy {
11
+ initial_interval: Some(prost_dur!(from_micros(15))),
12
+ backoff_coefficient: 1_000.,
13
+ maximum_interval: Some(prost_dur!(from_millis(1500))),
14
+ maximum_attempts: 4,
15
+ non_retryable_error_types: vec![],
16
+ },
17
+ timer_backoff_threshold: Some(Duration::from_secs(1)),
18
+ ..Default::default()
19
+ })
20
+ .await;
21
+ ctx.activity(ActivityOptions {
22
+ activity_type: "delay".to_string(),
23
+ start_to_close_timeout: Some(Duration::from_secs(20)),
24
+ input: "hi!".as_json_payload().expect("serializes fine"),
25
+ ..Default::default()
26
+ })
27
+ .await;
28
+ Ok(().into())
29
+ }
@@ -0,0 +1,130 @@
1
+ use futures_util::{sink, stream::FuturesUnordered, FutureExt, StreamExt};
2
+ use rand::{prelude::Distribution, rngs::SmallRng, Rng, SeedableRng};
3
+ use std::{future, time::Duration};
4
+ use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
5
+ use temporal_sdk::{ActContext, ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
6
+ use temporal_sdk_core_protos::coresdk::{AsJsonPayloadExt, FromJsonPayloadExt, IntoPayloadsExt};
7
+ use temporal_sdk_core_test_utils::CoreWfStarter;
8
+ use tokio_util::sync::CancellationToken;
9
+
10
+ const FUZZY_SIG: &str = "fuzzy_sig";
11
+
12
+ #[derive(serde::Serialize, serde::Deserialize, Copy, Clone)]
13
+ enum FuzzyWfAction {
14
+ Shutdown,
15
+ DoAct,
16
+ DoLocalAct,
17
+ }
18
+
19
+ struct FuzzyWfActionSampler;
20
+ impl Distribution<FuzzyWfAction> for FuzzyWfActionSampler {
21
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> FuzzyWfAction {
22
+ let v: u8 = rng.gen_range(1..=2);
23
+ match v {
24
+ 1 => FuzzyWfAction::DoAct,
25
+ 2 => FuzzyWfAction::DoLocalAct,
26
+ _ => unreachable!(),
27
+ }
28
+ }
29
+ }
30
+
31
+ async fn echo(_ctx: ActContext, echo_me: String) -> Result<String, anyhow::Error> {
32
+ Ok(echo_me)
33
+ }
34
+
35
+ async fn fuzzy_wf_def(ctx: WfContext) -> WorkflowResult<()> {
36
+ let sigchan = ctx
37
+ .make_signal_channel(FUZZY_SIG)
38
+ .map(|sd| FuzzyWfAction::from_json_payload(&sd.input[0]).expect("Can deserialize signal"));
39
+ let done = CancellationToken::new();
40
+ let done_setter = done.clone();
41
+
42
+ sigchan
43
+ .take_until(done.cancelled())
44
+ .for_each_concurrent(None, |action| {
45
+ let fut = match action {
46
+ FuzzyWfAction::DoAct => ctx
47
+ .activity(ActivityOptions {
48
+ activity_type: "echo_activity".to_string(),
49
+ start_to_close_timeout: Some(Duration::from_secs(5)),
50
+ input: "hi!".as_json_payload().expect("serializes fine"),
51
+ ..Default::default()
52
+ })
53
+ .map(|_| ())
54
+ .boxed(),
55
+ FuzzyWfAction::DoLocalAct => ctx
56
+ .local_activity(LocalActivityOptions {
57
+ activity_type: "echo_activity".to_string(),
58
+ start_to_close_timeout: Some(Duration::from_secs(5)),
59
+ input: "hi!".as_json_payload().expect("serializes fine"),
60
+ ..Default::default()
61
+ })
62
+ .map(|_| ())
63
+ .boxed(),
64
+ FuzzyWfAction::Shutdown => {
65
+ done_setter.cancel();
66
+ future::ready(()).boxed()
67
+ }
68
+ };
69
+ fut
70
+ })
71
+ .await;
72
+
73
+ Ok(().into())
74
+ }
75
+
76
+ #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
77
+ async fn fuzzy_workflow() {
78
+ let num_workflows = 200;
79
+ let wf_name = "fuzzy_wf";
80
+ let mut starter = CoreWfStarter::new("fuzzy_workflow");
81
+ starter.max_wft(25).max_cached_workflows(25).max_at(25);
82
+ // .enable_wf_state_input_recording();
83
+ let mut worker = starter.worker().await;
84
+ worker.register_wf(wf_name.to_owned(), fuzzy_wf_def);
85
+ worker.register_activity("echo_activity", echo);
86
+ let client = starter.get_client().await;
87
+
88
+ let mut workflow_handles = vec![];
89
+ for i in 0..num_workflows {
90
+ let wfid = format!("{wf_name}_{i}");
91
+ let rid = worker
92
+ .submit_wf(
93
+ wfid.clone(),
94
+ wf_name.to_owned(),
95
+ vec![],
96
+ WorkflowOptions::default(),
97
+ )
98
+ .await
99
+ .unwrap();
100
+ workflow_handles.push(client.get_untyped_workflow_handle(wfid, rid));
101
+ }
102
+
103
+ let rng = SmallRng::seed_from_u64(523189);
104
+ let mut actions: Vec<FuzzyWfAction> = rng.sample_iter(FuzzyWfActionSampler).take(15).collect();
105
+ actions.push(FuzzyWfAction::Shutdown);
106
+
107
+ let sig_sender = async {
108
+ for action in actions {
109
+ let sends: FuturesUnordered<_> = (0..num_workflows)
110
+ .map(|i| {
111
+ client.signal_workflow_execution(
112
+ format!("{wf_name}_{i}"),
113
+ "".to_string(),
114
+ FUZZY_SIG.to_string(),
115
+ [action.as_json_payload().expect("Serializes ok")].into_payloads(),
116
+ None,
117
+ )
118
+ })
119
+ .collect();
120
+ sends
121
+ .map(|_| Ok(()))
122
+ .forward(sink::drain())
123
+ .await
124
+ .expect("Sending signals works");
125
+ tokio::time::sleep(Duration::from_secs(1)).await;
126
+ }
127
+ };
128
+ let (r1, _) = tokio::join!(worker.run_until_done(), sig_sender);
129
+ r1.unwrap();
130
+ }