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,515 @@
1
+ //! This module implements support for downloading and running ephemeral test
2
+ //! servers useful for testing.
3
+
4
+ use anyhow::anyhow;
5
+ use flate2::read::GzDecoder;
6
+ use futures::StreamExt;
7
+ use serde::Deserialize;
8
+ use std::{
9
+ fs::OpenOptions,
10
+ path::{Path, PathBuf},
11
+ };
12
+ use temporal_client::ClientOptionsBuilder;
13
+ use tokio::{
14
+ task::spawn_blocking,
15
+ time::{sleep, Duration},
16
+ };
17
+ use tokio_util::io::{StreamReader, SyncIoBridge};
18
+ use url::Url;
19
+ use zip::read::read_zipfile_from_stream;
20
+
21
+ #[cfg(target_family = "unix")]
22
+ use std::os::unix::fs::OpenOptionsExt;
23
+ use std::process::Stdio;
24
+
25
+ /// Configuration for Temporalite.
26
+ #[derive(Debug, Clone, derive_builder::Builder)]
27
+ pub struct TemporaliteConfig {
28
+ /// Required path to executable or download info.
29
+ pub exe: EphemeralExe,
30
+ /// Namespace to use.
31
+ #[builder(default = "\"default\".to_owned()")]
32
+ pub namespace: String,
33
+ /// IP to bind to.
34
+ #[builder(default = "\"127.0.0.1\".to_owned()")]
35
+ pub ip: String,
36
+ /// Port to use or obtains a free one if none given.
37
+ #[builder(default)]
38
+ pub port: Option<u16>,
39
+ /// Sqlite DB filename if persisting or non-persistent if none.
40
+ #[builder(default)]
41
+ pub db_filename: Option<String>,
42
+ /// Whether to enable the UI.
43
+ #[builder(default)]
44
+ pub ui: bool,
45
+ /// Log format and level
46
+ #[builder(default = "(\"pretty\".to_owned(), \"warn\".to_owned())")]
47
+ pub log: (String, String),
48
+ /// Additional arguments to Temporalite.
49
+ #[builder(default)]
50
+ pub extra_args: Vec<String>,
51
+ }
52
+
53
+ impl TemporaliteConfig {
54
+ /// Start a Temporalite server.
55
+ pub async fn start_server(&self) -> anyhow::Result<EphemeralServer> {
56
+ self.start_server_with_output(Stdio::inherit()).await
57
+ }
58
+
59
+ /// Start a Temporalite server with configurable stdout destination.
60
+ pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
61
+ // Get exe path
62
+ let exe_path = self.exe.get_or_download("temporalite").await?;
63
+
64
+ // Get free port if not already given
65
+ let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
66
+
67
+ // Build arg set
68
+ let mut args = vec![
69
+ "start".to_owned(),
70
+ "--port".to_owned(),
71
+ port.to_string(),
72
+ "--namespace".to_owned(),
73
+ self.namespace.clone(),
74
+ "--ip".to_owned(),
75
+ self.ip.clone(),
76
+ "--log-format".to_owned(),
77
+ self.log.0.clone(),
78
+ "--log-level".to_owned(),
79
+ self.log.1.clone(),
80
+ ];
81
+ if let Some(db_filename) = &self.db_filename {
82
+ args.push("--filename".to_owned());
83
+ args.push(db_filename.clone());
84
+ } else {
85
+ args.push("--ephemeral".to_owned());
86
+ }
87
+ if !self.ui {
88
+ args.push("--headless".to_owned());
89
+ }
90
+ args.extend(self.extra_args.clone());
91
+
92
+ // Start
93
+ EphemeralServer::start(EphemeralServerConfig {
94
+ exe_path,
95
+ port,
96
+ args,
97
+ has_test_service: false,
98
+ output,
99
+ })
100
+ .await
101
+ }
102
+ }
103
+
104
+ /// Configuration for the test server.
105
+ #[derive(Debug, Clone, derive_builder::Builder)]
106
+ pub struct TestServerConfig {
107
+ /// Required path to executable or download info.
108
+ pub exe: EphemeralExe,
109
+ /// Port to use or obtains a free one if none given.
110
+ #[builder(default)]
111
+ pub port: Option<u16>,
112
+ /// Additional arguments to the test server.
113
+ #[builder(default)]
114
+ pub extra_args: Vec<String>,
115
+ }
116
+
117
+ impl TestServerConfig {
118
+ /// Start a test server.
119
+ pub async fn start_server(&self) -> anyhow::Result<EphemeralServer> {
120
+ self.start_server_with_output(Stdio::inherit()).await
121
+ }
122
+
123
+ /// Start a test server with configurable stdout.
124
+ pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
125
+ // Get exe path
126
+ let exe_path = self.exe.get_or_download("temporal-test-server").await?;
127
+
128
+ // Get free port if not already given
129
+ let port = self.port.unwrap_or_else(|| get_free_port("0.0.0.0"));
130
+
131
+ // Build arg set
132
+ let mut args = vec![port.to_string()];
133
+ args.extend(self.extra_args.clone());
134
+
135
+ // Start
136
+ EphemeralServer::start(EphemeralServerConfig {
137
+ exe_path,
138
+ port,
139
+ args,
140
+ has_test_service: true,
141
+ output,
142
+ })
143
+ .await
144
+ }
145
+ }
146
+
147
+ struct EphemeralServerConfig {
148
+ exe_path: PathBuf,
149
+ port: u16,
150
+ args: Vec<String>,
151
+ has_test_service: bool,
152
+ output: Stdio,
153
+ }
154
+
155
+ /// Server that will be stopped when dropped.
156
+ #[derive(Debug)]
157
+ pub struct EphemeralServer {
158
+ /// gRPC target host:port for the server frontend.
159
+ pub target: String,
160
+ /// Whether the target implements the gRPC TestService
161
+ pub has_test_service: bool,
162
+ child: tokio::process::Child,
163
+ }
164
+
165
+ impl EphemeralServer {
166
+ async fn start(config: EphemeralServerConfig) -> anyhow::Result<EphemeralServer> {
167
+ // Start process
168
+ // TODO(cretz): Offer stdio suppression?
169
+ let child = tokio::process::Command::new(config.exe_path)
170
+ .args(config.args)
171
+ .stdin(Stdio::null())
172
+ .stdout(config.output)
173
+ .spawn()?;
174
+ let target = format!("127.0.0.1:{}", config.port);
175
+ let target_url = format!("http://{}", target);
176
+ let success = Ok(EphemeralServer {
177
+ target,
178
+ has_test_service: config.has_test_service,
179
+ child,
180
+ });
181
+
182
+ // Try to connect every 100ms for 5s
183
+ // TODO(cretz): Some other way, e.g. via stdout, to know whether the
184
+ // server is up?
185
+ let client_options = ClientOptionsBuilder::default()
186
+ .identity("online_checker".to_owned())
187
+ .target_url(Url::parse(&target_url)?)
188
+ .client_name("online-checker".to_owned())
189
+ .client_version("0.1.0".to_owned())
190
+ .build()?;
191
+ for _ in 0..50 {
192
+ sleep(Duration::from_millis(100)).await;
193
+ if client_options
194
+ .connect_no_namespace(None, None)
195
+ .await
196
+ .is_ok()
197
+ {
198
+ return success;
199
+ }
200
+ }
201
+ Err(anyhow!("Failed connecting to test server after 5 seconds"))
202
+ }
203
+
204
+ /// Shutdown the server (i.e. kill the child process). This does not attempt
205
+ /// a kill if the child process appears completed, but such a check is not
206
+ /// atomic so a kill could still fail as completed if completed just before
207
+ /// kill.
208
+ #[cfg(not(target_family = "unix"))]
209
+ pub async fn shutdown(&mut self) -> anyhow::Result<()> {
210
+ // Only kill if there is a PID
211
+ if self.child.id().is_some() {
212
+ Ok(self.child.kill().await?)
213
+ } else {
214
+ Ok(())
215
+ }
216
+ }
217
+
218
+ /// Shutdown the server (i.e. kill the child process). This does not attempt
219
+ /// a kill if the child process appears completed, but such a check is not
220
+ /// atomic so a kill could still fail as completed if completed just before
221
+ /// kill.
222
+ #[cfg(target_family = "unix")]
223
+ pub async fn shutdown(&mut self) -> anyhow::Result<()> {
224
+ // For whatever reason, Tokio is not properly waiting on result
225
+ // after sending kill in some cases which is causing defunct zombie
226
+ // processes to remain and kill() to hang. Therefore, we are sending
227
+ // SIGKILL and waiting on the process ourselves using a low-level call.
228
+ //
229
+ // WARNING: This is based on empirical evidence starting a Python test
230
+ // run on Linux with Python 3.7 (does not happen on Python 3.10 nor does
231
+ // it happen on Temporalite nor does it happen in Rust integration
232
+ // tests). Don't alter without running that scenario. EX: SIGINT works but not SIGKILL
233
+ if let Some(pid) = self.child.id() {
234
+ let nix_pid = nix::unistd::Pid::from_raw(pid as i32);
235
+ Ok(spawn_blocking(move || {
236
+ nix::sys::signal::kill(nix_pid, nix::sys::signal::Signal::SIGINT)?;
237
+ nix::sys::wait::waitpid(Some(nix_pid), None)
238
+ })
239
+ .await?
240
+ .map(|_| ())?)
241
+ } else {
242
+ Ok(())
243
+ }
244
+ }
245
+ }
246
+
247
+ /// Where to find an executable. Can be a path or download.
248
+ #[derive(Debug, Clone)]
249
+ pub enum EphemeralExe {
250
+ /// Existing path on the filesystem for the executable.
251
+ ExistingPath(String),
252
+ /// Download the executable if not already there.
253
+ CachedDownload {
254
+ /// Which version to download.
255
+ version: EphemeralExeVersion,
256
+ /// Destination directory or the user temp directory if none set.
257
+ dest_dir: Option<String>,
258
+ },
259
+ }
260
+
261
+ /// Which version of the exe to download.
262
+ #[derive(Debug, Clone)]
263
+ pub enum EphemeralExeVersion {
264
+ /// Use a default version for the given SDK name and version.
265
+ Default {
266
+ /// Name of the SDK to get the default for.
267
+ sdk_name: String,
268
+ /// Version of the SDK to get the default for.
269
+ sdk_version: String,
270
+ },
271
+ /// Specific version.
272
+ Fixed(String),
273
+ }
274
+
275
+ #[derive(Deserialize, Debug)]
276
+ #[serde(rename_all = "camelCase")]
277
+ struct DownloadInfo {
278
+ archive_url: String,
279
+ file_to_extract: String,
280
+ }
281
+
282
+ impl EphemeralExe {
283
+ async fn get_or_download(&self, artifact_name: &str) -> anyhow::Result<PathBuf> {
284
+ match self {
285
+ EphemeralExe::ExistingPath(exe_path) => {
286
+ let path = PathBuf::from(exe_path);
287
+ if !path.exists() {
288
+ return Err(anyhow!("Exe path does not exist"));
289
+ }
290
+ Ok(path)
291
+ }
292
+ EphemeralExe::CachedDownload { version, dest_dir } => {
293
+ let dest_dir = dest_dir
294
+ .as_ref()
295
+ .map(PathBuf::from)
296
+ .unwrap_or_else(std::env::temp_dir);
297
+ let (platform, out_ext) = match std::env::consts::OS {
298
+ "windows" => ("windows", ".exe"),
299
+ "macos" => ("darwin", ""),
300
+ _ => ("linux", ""),
301
+ };
302
+ // Create dest file based on SDK name/version or fixed version
303
+ let dest = dest_dir.join(match version {
304
+ EphemeralExeVersion::Default {
305
+ sdk_name,
306
+ sdk_version,
307
+ } => format!("{}-{}-{}{}", artifact_name, sdk_name, sdk_version, out_ext),
308
+ EphemeralExeVersion::Fixed(version) => {
309
+ format!("{}-{}{}", artifact_name, version, out_ext)
310
+ }
311
+ });
312
+ debug!(
313
+ "Lazily downloading or using existing exe at {}",
314
+ dest.display()
315
+ );
316
+
317
+ // If it already exists, skip
318
+ if dest.exists() {
319
+ return Ok(dest);
320
+ }
321
+
322
+ // Get info about the proper archive and in-archive file
323
+ let arch = match std::env::consts::ARCH {
324
+ "x86_64" => "amd64",
325
+ "arm" | "aarch64" => "arm64",
326
+ other => return Err(anyhow!("Unsupported arch: {}", other)),
327
+ };
328
+ let mut get_info_params = vec![("arch", arch), ("platform", platform)];
329
+ let version_name = match version {
330
+ EphemeralExeVersion::Default {
331
+ sdk_name,
332
+ sdk_version,
333
+ } => {
334
+ get_info_params.push(("sdk-name", sdk_name.as_str()));
335
+ get_info_params.push(("sdk-version", sdk_version.as_str()));
336
+ "default"
337
+ }
338
+ EphemeralExeVersion::Fixed(version) => version,
339
+ };
340
+ let client = reqwest::Client::new();
341
+ let info: DownloadInfo = client
342
+ .get(format!(
343
+ "https://temporal.download/{}/{}",
344
+ artifact_name, version_name
345
+ ))
346
+ .query(&get_info_params)
347
+ .send()
348
+ .await?
349
+ .json()
350
+ .await?;
351
+
352
+ // Attempt download, looping because it could have waited for
353
+ // concurrent one to finish
354
+ loop {
355
+ if lazy_download_exe(
356
+ &client,
357
+ &info.archive_url,
358
+ Path::new(&info.file_to_extract),
359
+ &dest,
360
+ )
361
+ .await?
362
+ {
363
+ return Ok(dest);
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
370
+
371
+ fn get_free_port(bind_ip: &str) -> u16 {
372
+ // Can just ask OS to give us a port then close socket. OS's don't give that
373
+ // port back to anyone else anytime soon.
374
+ std::net::TcpListener::bind(format!("{}:0", bind_ip))
375
+ .unwrap()
376
+ .local_addr()
377
+ .unwrap()
378
+ .port()
379
+ }
380
+
381
+ /// Returns false if we successfully waited for another download to complete, or
382
+ /// true if the destination is known to exist. Should call again if false is
383
+ /// returned.
384
+ async fn lazy_download_exe(
385
+ client: &reqwest::Client,
386
+ uri: &str,
387
+ file_to_extract: &Path,
388
+ dest: &Path,
389
+ ) -> anyhow::Result<bool> {
390
+ // If it already exists, do not extract
391
+ if dest.exists() {
392
+ return Ok(true);
393
+ }
394
+
395
+ // We only want to download if we're not already downloading. To avoid some
396
+ // kind of global lock, we'll just create the file eagerly w/ a temp
397
+ // filename and delete it on failure or move it on success. If the temp file
398
+ // already exists, we'll wait a bit and re-run this.
399
+ let temp_dest_str = format!("{}{}", dest.to_str().unwrap(), ".downloading");
400
+ let temp_dest = Path::new(&temp_dest_str);
401
+ // Try to open file, using a file mode on unix families
402
+ #[cfg(target_family = "unix")]
403
+ let file = OpenOptions::new()
404
+ .create_new(true)
405
+ .write(true)
406
+ .mode(0o755)
407
+ .open(temp_dest);
408
+ #[cfg(not(target_family = "unix"))]
409
+ let file = OpenOptions::new()
410
+ .create_new(true)
411
+ .write(true)
412
+ .open(temp_dest);
413
+ // This match only gets Ok if the file was downloaded and extracted to the
414
+ // temporary path
415
+ match file {
416
+ Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {
417
+ // Since it already exists, we'll try once a second for 20 seconds
418
+ // to wait for it to be done, then return false so the caller can
419
+ // try again.
420
+ for _ in 0..20 {
421
+ sleep(Duration::from_secs(1)).await;
422
+ if !temp_dest.exists() {
423
+ return Ok(false);
424
+ }
425
+ }
426
+ Err(anyhow!(
427
+ "Temp download file at {} not complete after 20 seconds. \
428
+ Make sure another download isn't running for too long and delete the temp file.",
429
+ temp_dest.display()
430
+ ))
431
+ }
432
+ Err(err) => Err(err.into()),
433
+ // If the dest was added since, just remove temp file
434
+ Ok(_) if dest.exists() => {
435
+ std::fs::remove_file(temp_dest)?;
436
+ return Ok(true);
437
+ }
438
+ // Download and extract the binary
439
+ Ok(mut temp_file) => {
440
+ info!("Downloading {} to {}", uri, dest.display());
441
+ download_and_extract(client, uri, file_to_extract, &mut temp_file)
442
+ .await
443
+ .map_err(|err| {
444
+ // Failed to download, just remove file
445
+ if let Err(err) = std::fs::remove_file(temp_dest) {
446
+ warn!(
447
+ "Failed removing temp file at {}: {:?}",
448
+ temp_dest.display(),
449
+ err
450
+ );
451
+ }
452
+ err
453
+ })
454
+ }
455
+ }?;
456
+ // Now that file should be dropped, we can rename
457
+ std::fs::rename(temp_dest, dest)?;
458
+ Ok(true)
459
+ }
460
+
461
+ async fn download_and_extract(
462
+ client: &reqwest::Client,
463
+ uri: &str,
464
+ file_to_extract: &Path,
465
+ dest: &mut std::fs::File,
466
+ ) -> anyhow::Result<()> {
467
+ // Start download. We are using streaming here to extract the file from the
468
+ // tarball or zip instead of loading into memory for Cursor/Seek.
469
+ let resp = client.get(uri).send().await?;
470
+ // We have to map the error type to an io error
471
+ let stream = resp
472
+ .bytes_stream()
473
+ .map(|item| item.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err)));
474
+
475
+ // Since our tar/zip impls use sync IO, we have to create a bridge and run
476
+ // in a blocking closure.
477
+ let mut reader = SyncIoBridge::new(StreamReader::new(stream));
478
+ let tarball = if uri.ends_with(".tar.gz") {
479
+ true
480
+ } else if uri.ends_with(".zip") {
481
+ false
482
+ } else {
483
+ return Err(anyhow!("URI not .tar.gz or .zip"));
484
+ };
485
+ let file_to_extract = file_to_extract.to_path_buf();
486
+ let mut dest = dest.try_clone()?;
487
+
488
+ spawn_blocking(move || {
489
+ if tarball {
490
+ for entry in tar::Archive::new(GzDecoder::new(reader)).entries()? {
491
+ let mut entry = entry?;
492
+ if entry.path()? == file_to_extract {
493
+ std::io::copy(&mut entry, &mut dest)?;
494
+ return Ok(());
495
+ }
496
+ }
497
+ Err(anyhow!("Unable to find file in tarball"))
498
+ } else {
499
+ loop {
500
+ // This is the way to stream a zip file without creating an archive
501
+ // that requires Seek.
502
+ if let Some(mut file) = read_zipfile_from_stream(&mut reader)? {
503
+ // If this is the file we're expecting, extract it
504
+ if file.enclosed_name() == Some(&file_to_extract) {
505
+ std::io::copy(&mut file, &mut dest)?;
506
+ return Ok(());
507
+ }
508
+ } else {
509
+ return Err(anyhow!("Unable to find file in zip"));
510
+ }
511
+ }
512
+ }
513
+ })
514
+ .await?
515
+ }
@@ -0,0 +1,175 @@
1
+ #![warn(missing_docs)] // error if there are missing docs
2
+ #![allow(clippy::upper_case_acronyms)]
3
+
4
+ //! This crate provides a basis for creating new Temporal SDKs without completely starting from
5
+ //! scratch
6
+
7
+ #[cfg(test)]
8
+ #[macro_use]
9
+ pub extern crate assert_matches;
10
+ #[macro_use]
11
+ extern crate tracing;
12
+ extern crate core;
13
+
14
+ mod abstractions;
15
+ pub mod ephemeral_server;
16
+ mod log_export;
17
+ mod pollers;
18
+ mod protosext;
19
+ pub mod replay;
20
+ pub(crate) mod retry_logic;
21
+ pub(crate) mod telemetry;
22
+ mod worker;
23
+
24
+ #[cfg(test)]
25
+ mod core_tests;
26
+ #[cfg(test)]
27
+ #[macro_use]
28
+ mod test_help;
29
+
30
+ pub(crate) use temporal_sdk_core_api::errors;
31
+
32
+ pub use pollers::{
33
+ Client, ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryClient, RetryConfig,
34
+ TlsConfig, WorkflowClientTrait,
35
+ };
36
+ pub use telemetry::{
37
+ fetch_global_buffered_logs, telemetry_init, Logger, MetricTemporality, MetricsExporter,
38
+ OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder, TraceExporter,
39
+ };
40
+ pub use temporal_sdk_core_api as api;
41
+ pub use temporal_sdk_core_protos as protos;
42
+ pub use temporal_sdk_core_protos::TaskToken;
43
+ pub use url::Url;
44
+ pub use worker::{Worker, WorkerConfig, WorkerConfigBuilder};
45
+
46
+ use crate::{
47
+ replay::mock_client_from_history,
48
+ telemetry::metrics::{MetricsContext, METRIC_METER},
49
+ worker::client::WorkerClientBag,
50
+ };
51
+ use std::sync::Arc;
52
+ use temporal_client::{ConfiguredClient, TemporalServiceClientWithMetrics};
53
+ use temporal_sdk_core_api::{
54
+ errors::{CompleteActivityError, PollActivityError, PollWfError},
55
+ CoreLog, Worker as WorkerTrait,
56
+ };
57
+ use temporal_sdk_core_protos::{coresdk::ActivityHeartbeat, temporal::api::history::v1::History};
58
+
59
+ lazy_static::lazy_static! {
60
+ /// A process-wide unique string, which will be different on every startup
61
+ static ref PROCCESS_UNIQ_ID: String = {
62
+ uuid::Uuid::new_v4().simple().to_string()
63
+ };
64
+ }
65
+
66
+ /// Initialize a worker bound to a task queue.
67
+ ///
68
+ /// Lang implementations may pass in a [temporal_client::ConfiguredClient] directly (or a
69
+ /// [RetryClient] wrapping one, or a handful of other variants of the same idea). When they do so,
70
+ /// this function will always overwrite the client retry configuration, force the client to use the
71
+ /// namespace defined in the worker config, and set the client identity appropriately. IE: Use
72
+ /// [ClientOptions::connect_no_namespace], not [ClientOptions::connect].
73
+ pub fn init_worker<CT>(worker_config: WorkerConfig, client: CT) -> Worker
74
+ where
75
+ CT: Into<sealed::AnyClient>,
76
+ {
77
+ let client = {
78
+ let ll = client.into().into_inner();
79
+ let mut client = Client::new(*ll, worker_config.namespace.clone());
80
+ client.set_worker_build_id(worker_config.worker_build_id.clone());
81
+ if let Some(ref id_override) = worker_config.client_identity_override {
82
+ client.options_mut().identity = id_override.clone();
83
+ }
84
+ RetryClient::new(client, RetryConfig::default())
85
+ };
86
+ if client.namespace() != worker_config.namespace {
87
+ panic!("Passed in client is not bound to the same namespace as the worker");
88
+ }
89
+ let client_ident = client.get_options().identity.clone();
90
+ let sticky_q = sticky_q_name_for_worker(&client_ident, &worker_config);
91
+ let client_bag = Arc::new(WorkerClientBag::new(
92
+ client,
93
+ worker_config.namespace.clone(),
94
+ client_ident,
95
+ worker_config.worker_build_id.clone(),
96
+ worker_config.use_worker_versioning,
97
+ ));
98
+
99
+ let metrics = MetricsContext::top_level(worker_config.namespace.clone())
100
+ .with_task_q(worker_config.task_queue.clone());
101
+ Worker::new(worker_config, sticky_q, client_bag, metrics)
102
+ }
103
+
104
+ /// Create a worker for replaying a specific history. It will auto-shutdown as soon as the history
105
+ /// has finished being replayed. The provided client should be a mock, and this should only be used
106
+ /// for workflow testing purposes.
107
+ pub fn init_replay_worker(
108
+ mut config: WorkerConfig,
109
+ history: &History,
110
+ ) -> Result<Worker, anyhow::Error> {
111
+ info!(
112
+ task_queue = config.task_queue.as_str(),
113
+ "Registering replay worker"
114
+ );
115
+ config.max_cached_workflows = 1;
116
+ config.max_concurrent_wft_polls = 1;
117
+ config.no_remote_activities = true;
118
+ // Could possibly just use mocked pollers here?
119
+ let client = mock_client_from_history(history, config.task_queue.clone());
120
+ let run_id = history.extract_run_id_from_start()?.to_string();
121
+ let last_event = history.last_event_id();
122
+ let mut worker = Worker::new(config, None, Arc::new(client), MetricsContext::default());
123
+ worker.set_shutdown_on_run_reaches_event(run_id, last_event);
124
+ Ok(worker)
125
+ }
126
+
127
+ pub(crate) fn sticky_q_name_for_worker(
128
+ process_identity: &str,
129
+ config: &WorkerConfig,
130
+ ) -> Option<String> {
131
+ if config.max_cached_workflows > 0 {
132
+ Some(format!(
133
+ "{}-{}-{}",
134
+ &process_identity, &config.task_queue, *PROCCESS_UNIQ_ID
135
+ ))
136
+ } else {
137
+ None
138
+ }
139
+ }
140
+
141
+ mod sealed {
142
+ use super::*;
143
+
144
+ /// Allows passing different kinds of clients into things that want to be flexible. Motivating
145
+ /// use-case was worker initialization.
146
+ ///
147
+ /// Needs to exist in this crate to avoid blanket impl conflicts.
148
+ pub struct AnyClient(Box<ConfiguredClient<TemporalServiceClientWithMetrics>>);
149
+ impl AnyClient {
150
+ pub(crate) fn into_inner(self) -> Box<ConfiguredClient<TemporalServiceClientWithMetrics>> {
151
+ self.0
152
+ }
153
+ }
154
+
155
+ impl From<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>> for AnyClient {
156
+ fn from(c: RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>) -> Self {
157
+ Self(Box::new(c.into_inner()))
158
+ }
159
+ }
160
+ impl From<RetryClient<Client>> for AnyClient {
161
+ fn from(c: RetryClient<Client>) -> Self {
162
+ Self(Box::new(c.into_inner().into_inner()))
163
+ }
164
+ }
165
+ impl From<Arc<RetryClient<Client>>> for AnyClient {
166
+ fn from(c: Arc<RetryClient<Client>>) -> Self {
167
+ Self(Box::new(c.get_client().inner().clone()))
168
+ }
169
+ }
170
+ impl From<ConfiguredClient<TemporalServiceClientWithMetrics>> for AnyClient {
171
+ fn from(c: ConfiguredClient<TemporalServiceClientWithMetrics>) -> Self {
172
+ Self(Box::new(c))
173
+ }
174
+ }
175
+ }