@temporalio/core-bridge 1.8.6 → 1.9.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 (213) hide show
  1. package/Cargo.lock +670 -594
  2. package/Cargo.toml +2 -1
  3. package/lib/errors.js +6 -6
  4. package/lib/errors.js.map +1 -1
  5. package/lib/index.d.ts +17 -44
  6. package/lib/index.js.map +1 -1
  7. package/package.json +5 -6
  8. package/releases/aarch64-apple-darwin/index.node +0 -0
  9. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  10. package/releases/x86_64-apple-darwin/index.node +0 -0
  11. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  12. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  13. package/sdk-core/.github/workflows/heavy.yml +4 -0
  14. package/sdk-core/.github/workflows/per-pr.yml +96 -0
  15. package/sdk-core/ARCHITECTURE.md +1 -1
  16. package/sdk-core/Cargo.toml +10 -0
  17. package/sdk-core/LICENSE.txt +0 -2
  18. package/sdk-core/README.md +37 -21
  19. package/sdk-core/client/Cargo.toml +7 -4
  20. package/sdk-core/client/src/lib.rs +274 -142
  21. package/sdk-core/client/src/metrics.rs +68 -57
  22. package/sdk-core/client/src/raw.rs +191 -45
  23. package/sdk-core/client/src/retry.rs +20 -0
  24. package/sdk-core/client/src/worker_registry/mod.rs +264 -0
  25. package/sdk-core/client/src/workflow_handle/mod.rs +2 -1
  26. package/sdk-core/core/Cargo.toml +17 -19
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +7 -7
  29. package/sdk-core/core/src/core_tests/mod.rs +1 -0
  30. package/sdk-core/core/src/core_tests/queries.rs +42 -1
  31. package/sdk-core/core/src/core_tests/replay_flag.rs +29 -39
  32. package/sdk-core/core/src/core_tests/updates.rs +73 -0
  33. package/sdk-core/core/src/core_tests/workflow_tasks.rs +52 -1
  34. package/sdk-core/core/src/ephemeral_server/mod.rs +34 -11
  35. package/sdk-core/core/src/internal_flags.rs +7 -1
  36. package/sdk-core/core/src/lib.rs +19 -36
  37. package/sdk-core/core/src/protosext/mod.rs +12 -4
  38. package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
  39. package/sdk-core/core/src/replay/mod.rs +99 -48
  40. package/sdk-core/core/src/telemetry/log_export.rs +161 -28
  41. package/sdk-core/core/src/telemetry/metrics.rs +869 -248
  42. package/sdk-core/core/src/telemetry/mod.rs +153 -257
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
  44. package/sdk-core/core/src/test_help/mod.rs +64 -5
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +12 -2
  46. package/sdk-core/core/src/worker/activities.rs +276 -10
  47. package/sdk-core/core/src/worker/client/mocks.rs +18 -0
  48. package/sdk-core/core/src/worker/client.rs +16 -3
  49. package/sdk-core/core/src/worker/mod.rs +45 -28
  50. package/sdk-core/core/src/worker/slot_provider.rs +175 -0
  51. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +27 -34
  52. package/sdk-core/core/src/worker/workflow/history_update.rs +5 -2
  53. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +71 -95
  54. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +34 -22
  55. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +50 -34
  56. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +106 -92
  57. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +22 -21
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +386 -499
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -2
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +33 -26
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +198 -215
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +67 -63
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +88 -119
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +3 -1
  65. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +411 -0
  66. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +27 -26
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +319 -94
  68. package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
  69. package/sdk-core/core/src/worker/workflow/mod.rs +129 -58
  70. package/sdk-core/core/src/worker/workflow/run_cache.rs +16 -26
  71. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
  72. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +48 -43
  73. package/sdk-core/core-api/Cargo.toml +8 -7
  74. package/sdk-core/core-api/src/lib.rs +4 -12
  75. package/sdk-core/core-api/src/telemetry/metrics.rs +334 -0
  76. package/sdk-core/core-api/src/telemetry.rs +53 -42
  77. package/sdk-core/core-api/src/worker.rs +7 -0
  78. package/sdk-core/{.buildkite/docker → docker}/docker-compose.yaml +1 -1
  79. package/sdk-core/etc/dynamic-config.yaml +11 -1
  80. package/sdk-core/fsm/LICENSE.txt +0 -2
  81. package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
  82. package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
  83. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +1 -3
  84. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +2 -2
  85. package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -2
  86. package/sdk-core/sdk/Cargo.toml +2 -2
  87. package/sdk-core/sdk/src/lib.rs +85 -7
  88. package/sdk-core/sdk/src/workflow_context/options.rs +4 -0
  89. package/sdk-core/sdk/src/workflow_context.rs +43 -15
  90. package/sdk-core/sdk/src/workflow_future.rs +334 -204
  91. package/sdk-core/sdk-core-protos/Cargo.toml +3 -3
  92. package/sdk-core/sdk-core-protos/build.rs +14 -14
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +2 -0
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +99 -0
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +56 -0
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.gen.yaml +20 -0
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +11 -0
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +18 -0
  99. package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/annotations.proto +31 -0
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/http.proto +379 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/any.proto +162 -0
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/descriptor.proto +1212 -0
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/duration.proto +115 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/empty.proto +51 -0
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/timestamp.proto +144 -0
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/wrappers.proto +123 -0
  107. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/batch/v1/message.proto +12 -9
  108. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/command/v1/message.proto +11 -13
  109. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/common/v1/message.proto +33 -4
  110. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  111. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
  112. package/sdk-core/{protos/api_upstream/build/tools.go → sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto} +22 -6
  113. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/filter/v1/message.proto +2 -4
  114. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/history/v1/message.proto +21 -23
  115. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/namespace/v1/message.proto +2 -4
  116. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -0
  117. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -0
  118. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/replication/v1/message.proto +1 -3
  119. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/schedule/v1/message.proto +36 -20
  120. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +13 -0
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -0
  122. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -4
  123. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/update/v1/message.proto +1 -1
  124. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/version/v1/message.proto +2 -3
  125. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflow/v1/message.proto +24 -22
  126. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/request_response.proto +84 -32
  127. package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/service.proto +205 -47
  128. package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +57 -0
  129. package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +27 -0
  130. package/sdk-core/sdk-core-protos/src/history_builder.rs +67 -2
  131. package/sdk-core/sdk-core-protos/src/history_info.rs +1 -1
  132. package/sdk-core/sdk-core-protos/src/lib.rs +76 -3
  133. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  134. package/sdk-core/test-utils/Cargo.toml +6 -1
  135. package/sdk-core/test-utils/src/canned_histories.rs +3 -57
  136. package/sdk-core/test-utils/src/interceptors.rs +46 -0
  137. package/sdk-core/test-utils/src/lib.rs +106 -38
  138. package/sdk-core/tests/integ_tests/metrics_tests.rs +110 -15
  139. package/sdk-core/tests/integ_tests/queries_tests.rs +174 -3
  140. package/sdk-core/tests/integ_tests/update_tests.rs +908 -0
  141. package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -4
  142. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +44 -1
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
  144. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  145. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -4
  146. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +61 -0
  147. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +27 -2
  148. package/sdk-core/tests/integ_tests/workflow_tests.rs +142 -3
  149. package/sdk-core/tests/main.rs +2 -1
  150. package/sdk-core/tests/runner.rs +15 -2
  151. package/src/conversions.rs +107 -96
  152. package/src/helpers.rs +74 -0
  153. package/src/runtime.rs +29 -15
  154. package/src/worker.rs +14 -61
  155. package/ts/index.ts +23 -54
  156. package/sdk-core/.buildkite/docker/Dockerfile +0 -9
  157. package/sdk-core/.buildkite/docker/build.sh +0 -5
  158. package/sdk-core/.buildkite/docker/docker-compose-ci.yaml +0 -27
  159. package/sdk-core/.buildkite/pipeline.yml +0 -57
  160. package/sdk-core/.github/workflows/semgrep.yml +0 -25
  161. package/sdk-core/client/LICENSE.txt +0 -23
  162. package/sdk-core/core/LICENSE.txt +0 -23
  163. package/sdk-core/core/src/worker/workflow/bridge.rs +0 -35
  164. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +0 -215
  165. package/sdk-core/core-api/LICENSE.txt +0 -23
  166. package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +0 -2
  167. package/sdk-core/protos/api_upstream/Makefile +0 -80
  168. package/sdk-core/protos/api_upstream/api-linter.yaml +0 -40
  169. package/sdk-core/protos/api_upstream/buf.yaml +0 -9
  170. package/sdk-core/protos/api_upstream/build/go.mod +0 -7
  171. package/sdk-core/protos/api_upstream/build/go.sum +0 -5
  172. package/sdk-core/protos/api_upstream/go.mod +0 -6
  173. package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
  174. package/sdk-core/sdk/LICENSE.txt +0 -23
  175. package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
  176. /package/sdk-core/{.buildkite/docker → docker}/docker-compose-telem.yaml +0 -0
  177. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/docker-compose.yml +0 -0
  178. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/pipeline.yml +0 -0
  179. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/CODEOWNERS +0 -0
  180. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  181. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/publish-docs.yml +0 -0
  182. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
  183. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/LICENSE +0 -0
  184. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/README.md +0 -0
  185. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
  186. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
  187. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/common.proto +0 -0
  188. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
  189. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
  190. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/query.proto +0 -0
  191. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
  192. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
  193. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/update.proto +0 -0
  194. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
  195. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
  196. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/failure/v1/message.proto +0 -0
  197. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
  198. /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/query/v1/message.proto +0 -0
  199. /package/sdk-core/{protos → sdk-core-protos/protos}/google/rpc/status.proto +0 -0
  200. /package/sdk-core/{protos → sdk-core-protos/protos}/grpc/health/v1/health.proto +0 -0
  201. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
  202. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
  203. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
  204. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/common/common.proto +0 -0
  205. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/core_interface.proto +0 -0
  206. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/external_data/external_data.proto +0 -0
  207. /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
  208. /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/Makefile +0 -0
  209. /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/api-linter.yaml +0 -0
  210. /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/buf.yaml +0 -0
  211. /package/sdk-core/{protos/api_upstream → sdk-core-protos/protos/testsrv_upstream}/dependencies/gogoproto/gogo.proto +0 -0
  212. /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
  213. /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
@@ -0,0 +1,264 @@
1
+ //! This module enables the tracking of workers that are associated with a client instance.
2
+ //! This is needed to implement Eager Workflow Start, a latency optimization in which the client,
3
+ //! after reserving a slot, directly forwards a WFT to a local worker.
4
+
5
+ use parking_lot::RwLock;
6
+ use slotmap::SlotMap;
7
+ use std::collections::{hash_map::Entry::Vacant, HashMap};
8
+
9
+ use temporal_sdk_core_protos::temporal::api::workflowservice::v1::PollWorkflowTaskQueueResponse;
10
+
11
+ slotmap::new_key_type! {
12
+ /// Registration key for a worker
13
+ pub struct WorkerKey;
14
+ }
15
+
16
+ /// This trait is implemented by an object associated with a worker, which provides WFT processing slots.
17
+ #[cfg_attr(test, mockall::automock)]
18
+ pub trait SlotProvider: std::fmt::Debug {
19
+ /// The namespace for the WFTs that it can process.
20
+ fn namespace(&self) -> &str;
21
+ /// The task queue this provider listens to.
22
+ fn task_queue(&self) -> &str;
23
+ /// Try to reserve a slot on this worker.
24
+ fn try_reserve_wft_slot(&self) -> Option<Box<dyn Slot + Send>>;
25
+ }
26
+
27
+ /// This trait represents a slot reserved for processing a WFT by a worker.
28
+ #[cfg_attr(test, mockall::automock)]
29
+ pub trait Slot {
30
+ /// Consumes this slot by dispatching a WFT to its worker. This can only be called once.
31
+ fn schedule_wft(
32
+ self: Box<Self>,
33
+ task: PollWorkflowTaskQueueResponse,
34
+ ) -> Result<(), anyhow::Error>;
35
+ }
36
+
37
+ #[derive(PartialEq, Eq, Hash, Debug, Clone)]
38
+ struct SlotKey {
39
+ namespace: String,
40
+ task_queue: String,
41
+ }
42
+
43
+ impl SlotKey {
44
+ fn new(namespace: String, task_queue: String) -> SlotKey {
45
+ SlotKey {
46
+ namespace,
47
+ task_queue,
48
+ }
49
+ }
50
+ }
51
+
52
+ /// This is an inner class for [SlotManager] needed to hide the mutex.
53
+ #[derive(Default, Debug)]
54
+ struct SlotManagerImpl {
55
+ /// Maps keys, i.e., namespace#task_queue, to provider.
56
+ providers: HashMap<SlotKey, Box<dyn SlotProvider + Send + Sync>>,
57
+ /// Maps ids to keys in `providers`.
58
+ index: SlotMap<WorkerKey, SlotKey>,
59
+ }
60
+
61
+ impl SlotManagerImpl {
62
+ /// Factory method.
63
+ fn new() -> Self {
64
+ Self {
65
+ index: Default::default(),
66
+ providers: Default::default(),
67
+ }
68
+ }
69
+
70
+ fn try_reserve_wft_slot(
71
+ &self,
72
+ namespace: String,
73
+ task_queue: String,
74
+ ) -> Option<Box<dyn Slot + Send>> {
75
+ let key = SlotKey::new(namespace, task_queue);
76
+ if let Some(p) = self.providers.get(&key) {
77
+ if let Some(slot) = p.try_reserve_wft_slot() {
78
+ return Some(slot);
79
+ }
80
+ }
81
+ None
82
+ }
83
+
84
+ fn register(&mut self, provider: Box<dyn SlotProvider + Send + Sync>) -> Option<WorkerKey> {
85
+ let key = SlotKey::new(
86
+ provider.namespace().to_string(),
87
+ provider.task_queue().to_string(),
88
+ );
89
+ if let Vacant(p) = self.providers.entry(key.clone()) {
90
+ p.insert(provider);
91
+ Some(self.index.insert(key))
92
+ } else {
93
+ warn!("Ignoring registration for worker: {key:?}.");
94
+ None
95
+ }
96
+ }
97
+
98
+ fn unregister(&mut self, id: WorkerKey) {
99
+ if let Some(key) = self.index.remove(id) {
100
+ self.providers.remove(&key);
101
+ }
102
+ }
103
+
104
+ #[cfg(test)]
105
+ fn num_providers(&self) -> (usize, usize) {
106
+ (self.index.len(), self.providers.len())
107
+ }
108
+ }
109
+
110
+ /// Enables local workers to made themselves visible to a shared client instance.
111
+ /// There can only be one worker registered per namespace+queue_name+client, others will get ignored.
112
+ /// It also provides a convenient method to find compatible slots within the collection.
113
+ #[derive(Default, Debug)]
114
+ pub struct SlotManager {
115
+ manager: RwLock<SlotManagerImpl>,
116
+ }
117
+
118
+ impl SlotManager {
119
+ /// Factory method.
120
+ pub fn new() -> Self {
121
+ Self {
122
+ manager: RwLock::new(SlotManagerImpl::new()),
123
+ }
124
+ }
125
+
126
+ /// Try to reserve a compatible processing slot in any of the registered workers.
127
+ pub(crate) fn try_reserve_wft_slot(
128
+ &self,
129
+ namespace: String,
130
+ task_queue: String,
131
+ ) -> Option<Box<dyn Slot + Send>> {
132
+ self.manager
133
+ .read()
134
+ .try_reserve_wft_slot(namespace, task_queue)
135
+ }
136
+
137
+ /// Register a local worker that can provide WFT processing slots.
138
+ pub fn register(&self, provider: Box<dyn SlotProvider + Send + Sync>) -> Option<WorkerKey> {
139
+ self.manager.write().register(provider)
140
+ }
141
+
142
+ /// Unregister a provider, typically when its worker starts shutdown.
143
+ pub fn unregister(&self, id: WorkerKey) {
144
+ self.manager.write().unregister(id)
145
+ }
146
+
147
+ #[cfg(test)]
148
+ /// Returns (num_providers, num_buckets), where a bucket key is namespace+task_queue.
149
+ /// There is only one provider per bucket so `num_providers` should be equal to `num_buckets`.
150
+ pub fn num_providers(&self) -> (usize, usize) {
151
+ self.manager.read().num_providers()
152
+ }
153
+ }
154
+
155
+ #[cfg(test)]
156
+ mod tests {
157
+ use super::*;
158
+
159
+ fn new_mock_slot(with_error: bool) -> Box<MockSlot> {
160
+ let mut mock_slot = MockSlot::new();
161
+ if with_error {
162
+ mock_slot
163
+ .expect_schedule_wft()
164
+ .returning(|_| Err(anyhow::anyhow!("Changed my mind")));
165
+ } else {
166
+ mock_slot.expect_schedule_wft().returning(|_| Ok(()));
167
+ }
168
+ Box::new(mock_slot)
169
+ }
170
+
171
+ fn new_mock_provider(
172
+ namespace: String,
173
+ task_queue: String,
174
+ with_error: bool,
175
+ no_slots: bool,
176
+ ) -> MockSlotProvider {
177
+ let mut mock_provider = MockSlotProvider::new();
178
+ mock_provider
179
+ .expect_try_reserve_wft_slot()
180
+ .returning(move || {
181
+ if no_slots {
182
+ None
183
+ } else {
184
+ Some(new_mock_slot(with_error))
185
+ }
186
+ });
187
+ mock_provider.expect_namespace().return_const(namespace);
188
+ mock_provider.expect_task_queue().return_const(task_queue);
189
+ mock_provider
190
+ }
191
+
192
+ #[test]
193
+ fn registry_respects_registration_order() {
194
+ let mock_provider1 =
195
+ new_mock_provider("foo".to_string(), "bar_q".to_string(), false, false);
196
+ let mock_provider2 = new_mock_provider("foo".to_string(), "bar_q".to_string(), false, true);
197
+
198
+ let manager = SlotManager::new();
199
+ let some_slots = manager.register(Box::new(mock_provider1));
200
+ let no_slots = manager.register(Box::new(mock_provider2));
201
+ assert!(no_slots.is_none());
202
+
203
+ let mut found = 0;
204
+ for _ in 0..10 {
205
+ if manager
206
+ .try_reserve_wft_slot("foo".to_string(), "bar_q".to_string())
207
+ .is_some()
208
+ {
209
+ found += 1;
210
+ }
211
+ }
212
+ assert_eq!(found, 10);
213
+ assert_eq!((1, 1), manager.num_providers());
214
+
215
+ manager.unregister(some_slots.unwrap());
216
+ assert_eq!((0, 0), manager.num_providers());
217
+
218
+ let mock_provider1 =
219
+ new_mock_provider("foo".to_string(), "bar_q".to_string(), false, false);
220
+ let mock_provider2 = new_mock_provider("foo".to_string(), "bar_q".to_string(), false, true);
221
+
222
+ let no_slots = manager.register(Box::new(mock_provider2));
223
+ let some_slots = manager.register(Box::new(mock_provider1));
224
+ assert!(some_slots.is_none());
225
+
226
+ let mut not_found = 0;
227
+ for _ in 0..10 {
228
+ if manager
229
+ .try_reserve_wft_slot("foo".to_string(), "bar_q".to_string())
230
+ .is_none()
231
+ {
232
+ not_found += 1;
233
+ }
234
+ }
235
+ assert_eq!(not_found, 10);
236
+ assert_eq!((1, 1), manager.num_providers());
237
+ manager.unregister(no_slots.unwrap());
238
+ assert_eq!((0, 0), manager.num_providers());
239
+ }
240
+
241
+ #[test]
242
+ fn registry_keeps_one_provider_per_namespace() {
243
+ let manager = SlotManager::new();
244
+ let mut worker_keys = vec![];
245
+ for i in 0..10 {
246
+ let namespace = format!("myId{}", i % 3);
247
+ let mock_provider = new_mock_provider(namespace, "bar_q".to_string(), false, false);
248
+ worker_keys.push(manager.register(Box::new(mock_provider)));
249
+ }
250
+ assert_eq!((3, 3), manager.num_providers());
251
+
252
+ let count = worker_keys
253
+ .iter()
254
+ .filter(|key| key.is_some())
255
+ .fold(0, |count, key| {
256
+ manager.unregister(key.unwrap());
257
+ // Should be idempotent
258
+ manager.unregister(key.unwrap());
259
+ count + 1
260
+ });
261
+ assert_eq!(3, count);
262
+ assert_eq!((0, 0), manager.num_providers());
263
+ }
264
+ }
@@ -54,6 +54,7 @@ pub struct WorkflowHandle<ClientT, ResultT> {
54
54
  }
55
55
 
56
56
  /// Holds needed information to refer to a specific workflow run, or workflow execution chain
57
+ #[derive(Debug)]
57
58
  pub struct WorkflowExecutionInfo {
58
59
  /// Namespace the workflow lives in
59
60
  pub namespace: String,
@@ -100,7 +101,7 @@ where
100
101
  let server_res = self
101
102
  .client
102
103
  .clone()
103
- .workflow_client()
104
+ .workflow_client_mut()
104
105
  .get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
105
106
  namespace: self.info.namespace.to_string(),
106
107
  execution: Some(WorkflowExecution {
@@ -3,7 +3,7 @@ name = "temporal-sdk-core"
3
3
  version = "0.1.0"
4
4
  authors = ["Spencer Judge <spencer@temporal.io>", "Vitaly Arbuzov <vitaly@temporal.io>"]
5
5
  edition = "2021"
6
- license-file = "LICENSE.txt"
6
+ license-file = { workspace = true }
7
7
  description = "Library for building new Temporal SDKs"
8
8
  homepage = "https://temporal.io/"
9
9
  repository = "https://github.com/temporalio/sdk-core"
@@ -28,7 +28,7 @@ async-trait = "0.1"
28
28
  base64 = "0.21"
29
29
  console-subscriber = { version = "0.1", optional = true }
30
30
  crossbeam = "0.8"
31
- dashmap = "5.0"
31
+ dashmap = "5.5"
32
32
  derive_builder = "0.12"
33
33
  derive_more = "0.99"
34
34
  enum_dispatch = "0.3"
@@ -36,18 +36,19 @@ enum-iterator = "1.4"
36
36
  flate2 = { version = "1.0", optional = true }
37
37
  futures = "0.3"
38
38
  futures-util = "0.3"
39
- governor = "0.5"
39
+ governor = "0.6"
40
40
  http = "0.2"
41
41
  hyper = "0.14"
42
- itertools = "0.10"
42
+ itertools = "0.11"
43
43
  lazy_static = "1.4"
44
- lru = "0.10"
44
+ lru = "0.11"
45
45
  mockall = "0.11"
46
- nix = { version = "0.26", optional = true }
46
+ nix = { version = "0.27", optional = true, features = ["process", "signal"] }
47
47
  once_cell = "1.5"
48
- opentelemetry = { version = "0.18", features = ["rt-tokio"] }
49
- opentelemetry-otlp = { version = "0.11", features = ["tokio", "metrics"] }
50
- opentelemetry-prometheus = "0.11"
48
+ opentelemetry = { workspace = true, features = ["metrics"] }
49
+ opentelemetry_sdk = { version = "0.21", features = ["rt-tokio", "metrics"] }
50
+ opentelemetry-otlp = { version = "0.14", features = ["tokio", "metrics"] }
51
+ opentelemetry-prometheus = "0.14"
51
52
  parking_lot = { version = "0.12", features = ["send_guard"] }
52
53
  pin-project = "1.0"
53
54
  prometheus = "0.13"
@@ -59,51 +60,48 @@ ringbuf = "0.3"
59
60
  rmp-serde = { version = "1.1", optional = true }
60
61
  serde = "1.0"
61
62
  serde_json = "1.0"
62
- siphasher = "0.3"
63
+ siphasher = "1.0"
63
64
  slotmap = "1.0"
64
65
  tar = { version = "0.4", optional = true }
65
66
  thiserror = "1.0"
66
67
  tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
67
68
  tokio-util = { version = "0.7", features = ["io", "io-util"] }
68
69
  tokio-stream = "0.1"
69
- tonic = { version = "0.8", features = ["tls", "tls-roots"] }
70
+ tonic = { workspace = true, features = ["tls", "tls-roots"] }
70
71
  tracing = "0.1"
71
72
  tracing-futures = "0.2"
72
- tracing-opentelemetry = "0.18"
73
73
  tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter", "registry"] }
74
74
  url = "2.2"
75
75
  uuid = { version = "1.1", features = ["v4"] }
76
76
  zip = { version = "0.6.3", optional = true }
77
+ log = "0.4.20"
77
78
 
78
79
  # 1st party local deps
79
80
  [dependencies.temporal-sdk-core-api]
80
81
  path = "../core-api"
81
- version = "0.1"
82
+ features = ["otel_impls"]
82
83
 
83
84
  [dependencies.temporal-sdk-core-protos]
84
85
  path = "../sdk-core-protos"
85
- version = "0.1"
86
86
  features = ["history_builders"]
87
87
 
88
88
  [dependencies.temporal-client]
89
89
  path = "../client"
90
- version = "0.1"
91
90
 
92
91
  [dependencies.rustfsm]
93
92
  path = "../fsm"
94
- version = "0.1"
95
93
 
96
94
  [dev-dependencies]
97
95
  assert_matches = "1.4"
98
96
  bimap = "0.6.1"
99
97
  clap = { version = "4.0", features = ["derive"] }
100
- criterion = "0.4"
101
- rstest = "0.17"
98
+ criterion = "0.5"
99
+ rstest = "0.18"
102
100
  temporal-sdk-core-test-utils = { path = "../test-utils" }
103
101
  temporal-sdk = { path = "../sdk" }
104
102
 
105
103
  [build-dependencies]
106
- tonic-build = "0.8"
104
+ tonic-build = { workspace = true }
107
105
 
108
106
  [[test]]
109
107
  name = "integ_tests"
@@ -906,8 +906,10 @@ async fn activity_tasks_from_completion_reserve_slots() {
906
906
  mh.completion_asserts = Some(Box::new(|wftc| {
907
907
  // Make sure when we see the completion with the schedule act command that it does
908
908
  // not have the eager execution flag set the first time, and does the second.
909
- if let Some(Attributes::ScheduleActivityTaskCommandAttributes(attrs)) =
910
- wftc.commands.get(0).and_then(|cmd| cmd.attributes.as_ref())
909
+ if let Some(Attributes::ScheduleActivityTaskCommandAttributes(attrs)) = wftc
910
+ .commands
911
+ .first()
912
+ .and_then(|cmd| cmd.attributes.as_ref())
911
913
  {
912
914
  if attrs.activity_id == "1" {
913
915
  assert!(!attrs.request_eager_execution);
@@ -1,12 +1,13 @@
1
1
  use crate::{
2
2
  replay::DEFAULT_WORKFLOW_TYPE,
3
3
  test_help::{
4
- canned_histories, mock_sdk, mock_worker, single_hist_mock_sg, MockPollCfg, ResponseType,
4
+ build_fake_sdk, canned_histories, mock_sdk, mock_worker, single_hist_mock_sg, MockPollCfg,
5
+ ResponseType,
5
6
  },
6
- worker::{client::mocks::mock_workflow_client, ManagedWFFunc},
7
+ worker::client::mocks::mock_workflow_client,
7
8
  };
8
9
  use temporal_client::WorkflowOptions;
9
- use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext, WorkflowFunction, WorkflowResult};
10
+ use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext, WorkflowResult};
10
11
  use temporal_sdk_core_api::Worker;
11
12
  use temporal_sdk_core_protos::coresdk::{
12
13
  child_workflow::{child_workflow_result, ChildWorkflowCancellationType},
@@ -100,11 +101,10 @@ async fn parent_cancels_child_wf(ctx: WfContext) -> WorkflowResult<()> {
100
101
 
101
102
  #[tokio::test]
102
103
  async fn cancel_child_workflow() {
103
- let func = WorkflowFunction::new(parent_cancels_child_wf);
104
104
  let t = canned_histories::single_child_workflow_cancelled("child-id-1");
105
- let mut wfm = ManagedWFFunc::new(t, func, vec![]);
106
- wfm.process_all_activations().await.unwrap();
107
- wfm.shutdown().await.unwrap();
105
+ let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
106
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, parent_cancels_child_wf);
107
+ worker.run().await.unwrap();
108
108
  }
109
109
 
110
110
  #[rstest::rstest]
@@ -4,6 +4,7 @@ mod determinism;
4
4
  mod local_activities;
5
5
  mod queries;
6
6
  mod replay_flag;
7
+ mod updates;
7
8
  mod workers;
8
9
  mod workflow_cancels;
9
10
  mod workflow_tasks;
@@ -1,7 +1,7 @@
1
1
  use crate::{
2
2
  test_help::{
3
3
  build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, single_hist_mock_sg,
4
- MockPollCfg, ResponseType,
4
+ MockPollCfg, ResponseType, WorkerExt,
5
5
  },
6
6
  worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
7
7
  };
@@ -850,3 +850,44 @@ async fn legacy_query_combined_with_timer_fire_repro() {
850
850
  .unwrap();
851
851
  core.shutdown().await;
852
852
  }
853
+
854
+ #[tokio::test]
855
+ async fn build_id_set_properly_on_query_on_first_task() {
856
+ let wfid = "fake_wf_id";
857
+ let mut t = TestHistoryBuilder::default();
858
+ t.add_by_type(EventType::WorkflowExecutionStarted);
859
+ t.add_workflow_task_scheduled_and_started();
860
+ let tasks = VecDeque::from(vec![{
861
+ let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::AllHistory);
862
+ pr.queries.insert(
863
+ "q".to_string(),
864
+ WorkflowQuery {
865
+ query_type: "query-type".to_string(),
866
+ query_args: Some(b"hi".into()),
867
+ header: None,
868
+ },
869
+ );
870
+ pr
871
+ }]);
872
+ let mut mock_client = mock_workflow_client();
873
+ mock_client.expect_respond_legacy_query().times(0);
874
+ let mh = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
875
+ let mut mock = build_mock_pollers(mh);
876
+ mock.worker_cfg(|wc| {
877
+ wc.max_cached_workflows = 10;
878
+ wc.worker_build_id = "1.0".to_string();
879
+ });
880
+ let core = mock_worker(mock);
881
+
882
+ let task = core.poll_workflow_activation().await.unwrap();
883
+ assert_eq!(task.build_id_for_current_task, "1.0");
884
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
885
+ .await
886
+ .unwrap();
887
+ let task = core.poll_workflow_activation().await.unwrap();
888
+ assert_eq!(task.build_id_for_current_task, "1.0");
889
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
890
+ .await
891
+ .unwrap();
892
+ core.drain_pollers_and_shutdown().await;
893
+ }
@@ -1,26 +1,25 @@
1
1
  use crate::{
2
2
  test_help::{
3
- build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, MockPollCfg,
4
- ResponseType,
3
+ build_fake_sdk, build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker,
4
+ MockPollCfg, ResponseType,
5
5
  },
6
- worker::{client::mocks::mock_workflow_client, ManagedWFFunc, LEGACY_QUERY_ID},
6
+ worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
7
7
  };
8
8
  use rstest::{fixture, rstest};
9
9
  use std::{collections::VecDeque, time::Duration};
10
- use temporal_sdk::{WfContext, WorkflowFunction};
11
- use temporal_sdk_core_api::Worker;
10
+ use temporal_sdk::{WfContext, Worker, WorkflowFunction};
11
+ use temporal_sdk_core_api::Worker as CoreWorker;
12
12
  use temporal_sdk_core_protos::{
13
13
  coresdk::{
14
14
  workflow_activation::{workflow_activation_job, WorkflowActivationJob},
15
15
  workflow_completion::WorkflowActivationCompletion,
16
16
  },
17
- temporal::api::{
18
- enums::v1::{CommandType, EventType},
19
- query::v1::WorkflowQuery,
20
- },
21
- TestHistoryBuilder,
17
+ temporal::api::{enums::v1::EventType, query::v1::WorkflowQuery},
18
+ TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE,
19
+ };
20
+ use temporal_sdk_core_test_utils::{
21
+ interceptors::ActivationAssertionsInterceptor, query_ok, start_timer_cmd,
22
22
  };
23
- use temporal_sdk_core_test_utils::{query_ok, start_timer_cmd};
24
23
 
25
24
  fn timers_wf(num_timers: u32) -> WorkflowFunction {
26
25
  WorkflowFunction::new(move |command_sink: WfContext| async move {
@@ -32,38 +31,31 @@ fn timers_wf(num_timers: u32) -> WorkflowFunction {
32
31
  }
33
32
 
34
33
  #[fixture(num_timers = 1)]
35
- fn fire_happy_hist(num_timers: u32) -> ManagedWFFunc {
34
+ fn fire_happy_hist(num_timers: u32) -> Worker {
36
35
  let func = timers_wf(num_timers);
37
36
  // Add 1 b/c history takes # wf tasks, not timers
38
37
  let t = canned_histories::long_sequential_timers(num_timers as usize);
39
- ManagedWFFunc::new(t, func, vec![])
38
+ let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
39
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
40
+ worker
40
41
  }
41
42
 
42
43
  #[rstest]
43
44
  #[case::one_timer(fire_happy_hist(1), 1)]
44
45
  #[case::five_timers(fire_happy_hist(5), 5)]
45
46
  #[tokio::test]
46
- async fn replay_flag_is_correct(#[case] mut wfm: ManagedWFFunc, #[case] num_timers: usize) {
47
+ async fn replay_flag_is_correct(#[case] mut worker: Worker, #[case] num_timers: usize) {
47
48
  // Verify replay flag is correct by constructing a workflow manager that already has a complete
48
49
  // history fed into it. It should always be replaying, because history is complete.
49
50
 
50
- for _ in 1..=num_timers {
51
- let act = wfm.get_next_activation().await.unwrap();
52
- assert!(act.is_replaying);
53
- let commands = wfm.get_server_commands().commands;
54
- assert_eq!(commands.len(), 1);
55
- assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
51
+ let mut aai = ActivationAssertionsInterceptor::default();
52
+
53
+ for _ in 1..=num_timers + 1 {
54
+ aai.then(|a| assert!(a.is_replaying));
56
55
  }
57
56
 
58
- let act = wfm.get_next_activation().await.unwrap();
59
- assert!(act.is_replaying);
60
- let commands = wfm.get_server_commands().commands;
61
- assert_eq!(commands.len(), 1);
62
- assert_eq!(
63
- commands[0].command_type,
64
- CommandType::CompleteWorkflowExecution as i32
65
- );
66
- wfm.shutdown().await.unwrap();
57
+ worker.set_worker_interceptor(aai);
58
+ worker.run().await.unwrap();
67
59
  }
68
60
 
69
61
  #[tokio::test(flavor = "multi_thread")]
@@ -71,15 +63,14 @@ async fn replay_flag_is_correct_partial_history() {
71
63
  let func = timers_wf(1);
72
64
  // Add 1 b/c history takes # wf tasks, not timers
73
65
  let t = canned_histories::long_sequential_timers(2);
74
- let mut wfm =
75
- ManagedWFFunc::new_from_update(t.get_history_info(1).unwrap().into(), func, vec![]);
76
-
77
- let act = wfm.get_next_activation().await.unwrap();
78
- assert!(!act.is_replaying);
79
- let commands = wfm.get_server_commands().commands;
80
- assert_eq!(commands.len(), 1);
81
- assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
82
- wfm.shutdown().await.unwrap();
66
+ let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [1]));
67
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
68
+
69
+ let mut aai = ActivationAssertionsInterceptor::default();
70
+ aai.then(|a| assert!(!a.is_replaying));
71
+
72
+ worker.set_worker_interceptor(aai);
73
+ worker.run().await.unwrap();
83
74
  }
84
75
 
85
76
  #[tokio::test]
@@ -99,7 +90,6 @@ async fn replay_flag_correct_with_query() {
99
90
  let h = pr.history.as_mut().unwrap();
100
91
  h.events.truncate(5);
101
92
  pr.started_event_id = 3;
102
- dbg!(&pr.resp);
103
93
  pr
104
94
  },
105
95
  hist_to_poll_resp(&t, wfid.to_owned(), 2.into()),
@@ -0,0 +1,73 @@
1
+ use crate::test_help::{build_mock_pollers, mock_worker, MockPollCfg, ResponseType};
2
+ use temporal_sdk_core_api::Worker;
3
+ use temporal_sdk_core_protos::{
4
+ coresdk::{
5
+ workflow_activation::{workflow_activation_job, WorkflowActivationJob},
6
+ workflow_commands::{update_response::Response, CompleteWorkflowExecution, UpdateResponse},
7
+ workflow_completion::WorkflowActivationCompletion,
8
+ },
9
+ temporal::api::{common::v1::Payload, enums::v1::EventType},
10
+ TestHistoryBuilder,
11
+ };
12
+
13
+ #[tokio::test]
14
+ async fn replay_with_empty_first_task() {
15
+ let mut t = TestHistoryBuilder::default();
16
+ t.add_by_type(EventType::WorkflowExecutionStarted);
17
+ t.add_full_wf_task();
18
+ t.add_full_wf_task();
19
+ let accept_id = t.add_update_accepted("upd1", "update");
20
+ t.add_we_signaled("hi", vec![]);
21
+ t.add_full_wf_task();
22
+ t.add_update_completed(accept_id);
23
+ t.add_workflow_execution_completed();
24
+
25
+ let mock = MockPollCfg::from_resps(t, [ResponseType::AllHistory]);
26
+ let mut mock = build_mock_pollers(mock);
27
+ mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
28
+ let core = mock_worker(mock);
29
+
30
+ let task = core.poll_workflow_activation().await.unwrap();
31
+ assert_matches!(
32
+ task.jobs.as_slice(),
33
+ [
34
+ WorkflowActivationJob {
35
+ variant: Some(workflow_activation_job::Variant::DoUpdate(_)),
36
+ },
37
+ WorkflowActivationJob {
38
+ variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
39
+ },
40
+ ]
41
+ );
42
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
43
+ task.run_id,
44
+ UpdateResponse {
45
+ protocol_instance_id: "upd1".to_string(),
46
+ response: Some(Response::Accepted(())),
47
+ }
48
+ .into(),
49
+ ))
50
+ .await
51
+ .unwrap();
52
+
53
+ let task = core.poll_workflow_activation().await.unwrap();
54
+ assert_matches!(
55
+ task.jobs.as_slice(),
56
+ [WorkflowActivationJob {
57
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
58
+ }]
59
+ );
60
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
61
+ task.run_id,
62
+ vec![
63
+ UpdateResponse {
64
+ protocol_instance_id: "upd1".to_string(),
65
+ response: Some(Response::Completed(Payload::default())),
66
+ }
67
+ .into(),
68
+ CompleteWorkflowExecution { result: None }.into(),
69
+ ],
70
+ ))
71
+ .await
72
+ .unwrap();
73
+ }