@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
@@ -5,9 +5,13 @@
5
5
  extern crate tracing;
6
6
 
7
7
  pub mod canned_histories;
8
+ pub mod interceptors;
8
9
  pub mod wf_input_saver;
9
10
  pub mod workflows;
10
11
 
12
+ use anyhow::Context;
13
+ pub use temporal_sdk_core::replay::HistoryForReplay;
14
+
11
15
  use crate::{
12
16
  stream::{Stream, TryStreamExt},
13
17
  wf_input_saver::stream_to_file,
@@ -29,17 +33,19 @@ use temporal_sdk::{
29
33
  interceptors::{FailOnNondeterminismInterceptor, WorkerInterceptor},
30
34
  IntoActivityFunc, Worker, WorkflowFunction,
31
35
  };
36
+ #[cfg(feature = "ephemeral-server")]
37
+ use temporal_sdk_core::ephemeral_server::{EphemeralExe, EphemeralExeVersion};
32
38
  use temporal_sdk_core::{
33
- ephemeral_server::{EphemeralExe, EphemeralExeVersion},
34
39
  init_replay_worker, init_worker,
35
- replay::HistoryForReplay,
40
+ replay::ReplayWorkerInput,
41
+ telemetry::{build_otlp_metric_exporter, start_prometheus_metric_exporter},
36
42
  ClientOptions, ClientOptionsBuilder, CoreRuntime, WorkerConfigBuilder,
37
43
  };
38
44
  use temporal_sdk_core_api::{
39
45
  errors::{PollActivityError, PollWfError},
40
46
  telemetry::{
41
- Logger, MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
42
- TraceExportConfig, TraceExporter,
47
+ metrics::CoreMeter, Logger, OtelCollectorOptionsBuilder, PrometheusExporterOptionsBuilder,
48
+ TelemetryOptions, TelemetryOptionsBuilder,
43
49
  },
44
50
  Worker as CoreWorker,
45
51
  };
@@ -51,7 +57,10 @@ use temporal_sdk_core_protos::{
51
57
  },
52
58
  workflow_completion::WorkflowActivationCompletion,
53
59
  },
54
- temporal::api::{common::v1::Payload, history::v1::History},
60
+ temporal::api::{
61
+ common::v1::Payload, history::v1::History,
62
+ workflowservice::v1::StartWorkflowExecutionResponse,
63
+ },
55
64
  DEFAULT_ACTIVITY_TYPE,
56
65
  };
57
66
  use tokio::sync::{mpsc::unbounded_channel, OnceCell};
@@ -82,7 +91,7 @@ macro_rules! prost_dur {
82
91
  }
83
92
 
84
93
  /// Create a worker instance which will use the provided test name to base the task queue and wf id
85
- /// upon. Returns the instance and the task queue name (which is also the workflow id).
94
+ /// upon. Returns the instance.
86
95
  pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
87
96
  let mut starter = CoreWfStarter::new(test_name);
88
97
  let _ = starter.get_worker().await;
@@ -109,8 +118,8 @@ where
109
118
  .worker_build_id("test_bin_id")
110
119
  .build()
111
120
  .expect("Configuration options construct properly");
112
- let worker =
113
- init_replay_worker(worker_cfg, histories).expect("Replay worker must init properly");
121
+ let worker = init_replay_worker(ReplayWorkerInput::new(worker_cfg, histories))
122
+ .expect("Replay worker must init properly");
114
123
  Arc::new(worker)
115
124
  }
116
125
  pub fn replay_sdk_worker<I>(histories: I) -> Worker
@@ -126,7 +135,7 @@ where
126
135
  {
127
136
  let core = init_core_replay_stream("replay_worker_test", histories);
128
137
  let mut worker = Worker::new_from_core(core, "replay_q".to_string());
129
- worker.set_worker_interceptor(Box::new(FailOnNondeterminismInterceptor {}));
138
+ worker.set_worker_interceptor(FailOnNondeterminismInterceptor {});
130
139
  worker
131
140
  }
132
141
 
@@ -145,7 +154,9 @@ pub fn init_integ_telem() {
145
154
  let telemetry_options = get_integ_telem_options();
146
155
  let rt =
147
156
  CoreRuntime::new_assume_tokio(telemetry_options).expect("Core runtime inits cleanly");
148
- let _ = tracing::subscriber::set_global_default(rt.trace_subscriber());
157
+ if let Some(sub) = rt.telemetry().trace_subscriber() {
158
+ let _ = tracing::subscriber::set_global_default(sub);
159
+ }
149
160
  rt
150
161
  });
151
162
  }
@@ -194,6 +205,18 @@ impl CoreWfStarter {
194
205
  }
195
206
  }
196
207
 
208
+ /// Create a new starter with no initialized worker or runtime override. Useful for starting a
209
+ /// new worker on the same queue.
210
+ pub fn clone_no_worker(&self) -> Self {
211
+ Self {
212
+ task_queue_name: self.task_queue_name.clone(),
213
+ worker_config: self.worker_config.clone(),
214
+ workflow_options: self.workflow_options.clone(),
215
+ runtime_override: None,
216
+ initted_worker: Default::default(),
217
+ }
218
+ }
219
+
197
220
  pub async fn worker(&mut self) -> TestWorker {
198
221
  let w = self.get_worker().await;
199
222
  let tq = w.get_config().task_queue.clone();
@@ -236,6 +259,23 @@ impl CoreWfStarter {
236
259
  .unwrap()
237
260
  }
238
261
 
262
+ pub async fn eager_start_with_worker(
263
+ &self,
264
+ wf_name: impl Into<String>,
265
+ worker: &mut TestWorker,
266
+ ) -> StartWorkflowExecutionResponse {
267
+ assert!(self.workflow_options.enable_eager_workflow_start);
268
+ worker
269
+ .eager_submit_wf(
270
+ self.task_queue_name.clone(),
271
+ wf_name.into(),
272
+ vec![],
273
+ self.workflow_options.clone(),
274
+ )
275
+ .await
276
+ .unwrap()
277
+ }
278
+
239
279
  pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
240
280
  let iw = self.initted_worker.get().expect(
241
281
  "Worker must be initted before starting a workflow.\
@@ -275,7 +315,7 @@ impl CoreWfStarter {
275
315
  let with_id = HistoryForReplay::new(history, wf_id);
276
316
  let replay_worker = init_core_replay_preloaded(worker.task_queue(), [with_id]);
277
317
  worker.with_new_core_worker(replay_worker);
278
- worker.set_worker_interceptor(Box::new(FailOnNondeterminismInterceptor {}));
318
+ worker.set_worker_interceptor(FailOnNondeterminismInterceptor {});
279
319
  worker.run().await.unwrap();
280
320
  Ok(())
281
321
  }
@@ -366,23 +406,17 @@ pub struct TestWorker {
366
406
  /// If set true (default), and a client is available, we will fetch workflow results to
367
407
  /// determine when they have all completed.
368
408
  pub fetch_results: bool,
369
- iceptor: Option<TestWorkerCompletionIceptor>,
370
409
  }
371
410
  impl TestWorker {
372
411
  /// Create a new test worker
373
412
  pub fn new(core_worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
374
413
  let inner = Worker::new_from_core(core_worker.clone(), task_queue);
375
- let iceptor = TestWorkerCompletionIceptor::new(
376
- TestWorkerShutdownCond::NoAutoShutdown,
377
- Arc::new(inner.shutdown_handle()),
378
- );
379
414
  Self {
380
415
  inner,
381
416
  core_worker,
382
417
  client: None,
383
418
  started_workflows: Mutex::new(vec![]),
384
419
  fetch_results: true,
385
- iceptor: Some(iceptor),
386
420
  }
387
421
  }
388
422
 
@@ -443,6 +477,39 @@ impl TestWorker {
443
477
  }
444
478
  }
445
479
 
480
+ /// Similar to `submit_wf` but checking that the server returns the first
481
+ /// workflow task in the client response.
482
+ /// Note that this does not guarantee that the worker will execute this task eagerly.
483
+ pub async fn eager_submit_wf(
484
+ &self,
485
+ workflow_id: impl Into<String>,
486
+ workflow_type: impl Into<String>,
487
+ input: Vec<Payload>,
488
+ options: WorkflowOptions,
489
+ ) -> Result<StartWorkflowExecutionResponse, anyhow::Error> {
490
+ let c = self.client.as_ref().context("client needed for eager wf")?;
491
+ let wfid = workflow_id.into();
492
+ let res = c
493
+ .start_workflow(
494
+ input,
495
+ self.inner.task_queue().to_string(),
496
+ wfid.clone(),
497
+ workflow_type.into(),
498
+ None,
499
+ options,
500
+ )
501
+ .await?;
502
+ res.eager_workflow_task
503
+ .as_ref()
504
+ .context("no eager workflow task")?;
505
+ self.started_workflows.lock().push(WorkflowExecutionInfo {
506
+ namespace: c.namespace().to_string(),
507
+ workflow_id: wfid,
508
+ run_id: Some(res.run_id.clone()),
509
+ });
510
+ Ok(res)
511
+ }
512
+
446
513
  /// Runs until all expected workflows have completed
447
514
  pub async fn run_until_done(&mut self) -> Result<(), anyhow::Error> {
448
515
  self.run_until_done_intercepted(Option::<TestWorkerCompletionIceptor>::None)
@@ -452,9 +519,12 @@ impl TestWorker {
452
519
  /// See [Self::run_until_done], but allows configuration of some low-level interception.
453
520
  pub async fn run_until_done_intercepted(
454
521
  &mut self,
455
- interceptor: Option<impl WorkerInterceptor + 'static>,
522
+ next_interceptor: Option<impl WorkerInterceptor + 'static>,
456
523
  ) -> Result<(), anyhow::Error> {
457
- let mut iceptor = self.iceptor.take().unwrap();
524
+ let mut iceptor = TestWorkerCompletionIceptor::new(
525
+ TestWorkerShutdownCond::NoAutoShutdown,
526
+ Arc::new(self.inner.shutdown_handle()),
527
+ );
458
528
  // Automatically use results-based complete detection if we have a client
459
529
  if self.fetch_results {
460
530
  if let Some(c) = self.client.clone() {
@@ -464,9 +534,9 @@ impl TestWorker {
464
534
  );
465
535
  }
466
536
  }
467
- iceptor.next = interceptor.map(|i| Box::new(i) as Box<dyn WorkerInterceptor>);
537
+ iceptor.next = next_interceptor.map(|i| Box::new(i) as Box<dyn WorkerInterceptor>);
468
538
  let get_results_waiter = iceptor.wait_all_wfs();
469
- self.inner.set_worker_interceptor(Box::new(iceptor));
539
+ self.inner.set_worker_interceptor(iceptor);
470
540
  tokio::try_join!(self.inner.run(), get_results_waiter)?;
471
541
  Ok(())
472
542
  }
@@ -482,7 +552,6 @@ pub enum TestWorkerShutdownCond {
482
552
  pub struct TestWorkerCompletionIceptor {
483
553
  condition: TestWorkerShutdownCond,
484
554
  shutdown_handle: Arc<dyn Fn()>,
485
- every_activation: Option<BoxDynActivationHook>,
486
555
  next: Option<Box<dyn WorkerInterceptor>>,
487
556
  }
488
557
  impl TestWorkerCompletionIceptor {
@@ -490,7 +559,6 @@ impl TestWorkerCompletionIceptor {
490
559
  Self {
491
560
  condition,
492
561
  shutdown_handle,
493
- every_activation: None,
494
562
  next: None,
495
563
  }
496
564
  }
@@ -523,11 +591,8 @@ impl TestWorkerCompletionIceptor {
523
591
  #[async_trait::async_trait(?Send)]
524
592
  impl WorkerInterceptor for TestWorkerCompletionIceptor {
525
593
  async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
526
- if let Some(func) = self.every_activation.as_ref() {
527
- func(completion);
528
- }
529
594
  if completion.has_execution_ending() {
530
- info!("Workflow {} says it's finishing", &completion.run_id);
595
+ debug!("Workflow {} says it's finishing", &completion.run_id);
531
596
  }
532
597
  if let Some(n) = self.next.as_ref() {
533
598
  n.on_workflow_activation_completion(completion).await;
@@ -585,22 +650,24 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
585
650
  .ok()
586
651
  .map(|x| x.parse::<Url>().unwrap())
587
652
  {
588
- let opts = OtelCollectorOptions {
589
- url,
590
- headers: Default::default(),
591
- metric_periodicity: None,
592
- };
593
- ob.tracing(TraceExportConfig {
594
- filter: filter_string.clone(),
595
- exporter: TraceExporter::Otel(opts.clone()),
596
- });
597
- ob.metrics(MetricsExporter::Otel(opts));
653
+ let opts = OtelCollectorOptionsBuilder::default()
654
+ .url(url)
655
+ .build()
656
+ .unwrap();
657
+ ob.metrics(Arc::new(build_otlp_metric_exporter(opts).unwrap()) as Arc<dyn CoreMeter>);
598
658
  }
599
659
  if let Some(addr) = env::var(PROM_ENABLE_ENV_VAR)
600
660
  .ok()
601
661
  .map(|x| SocketAddr::new([127, 0, 0, 1].into(), x.parse().unwrap()))
602
662
  {
603
- ob.metrics(MetricsExporter::Prometheus(addr));
663
+ let prom_info = start_prometheus_metric_exporter(
664
+ PrometheusExporterOptionsBuilder::default()
665
+ .socket_addr(addr)
666
+ .build()
667
+ .unwrap(),
668
+ )
669
+ .unwrap();
670
+ ob.metrics(prom_info.meter as Arc<dyn CoreMeter>);
604
671
  }
605
672
  ob.logging(Logger::Console {
606
673
  filter: filter_string,
@@ -609,6 +676,7 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
609
676
  .unwrap()
610
677
  }
611
678
 
679
+ #[cfg(feature = "ephemeral-server")]
612
680
  pub fn default_cached_download() -> EphemeralExe {
613
681
  EphemeralExe::CachedDownload {
614
682
  version: EphemeralExeVersion::SDKDefault {
@@ -1,8 +1,15 @@
1
1
  use assert_matches::assert_matches;
2
- use std::{sync::Arc, time::Duration};
2
+ use std::{net::SocketAddr, sync::Arc, time::Duration};
3
3
  use temporal_client::{WorkflowClientTrait, WorkflowOptions, WorkflowService};
4
- use temporal_sdk_core::{init_worker, CoreRuntime};
5
- use temporal_sdk_core_api::{telemetry::MetricsExporter, worker::WorkerConfigBuilder, Worker};
4
+ use temporal_sdk_core::{init_worker, telemetry::start_prometheus_metric_exporter, CoreRuntime};
5
+ use temporal_sdk_core_api::{
6
+ telemetry::{
7
+ metrics::{CoreMeter, MetricAttributes, MetricParameters},
8
+ PrometheusExporterOptionsBuilder, TelemetryOptions,
9
+ },
10
+ worker::WorkerConfigBuilder,
11
+ Worker,
12
+ };
6
13
  use temporal_sdk_core_protos::{
7
14
  coresdk::{
8
15
  activity_result::ActivityExecutionResult,
@@ -23,7 +30,7 @@ use temporal_sdk_core_protos::{
23
30
  use temporal_sdk_core_test_utils::{
24
31
  get_integ_server_options, get_integ_telem_options, CoreWfStarter, NAMESPACE,
25
32
  };
26
- use tokio::{join, sync::Barrier};
33
+ use tokio::{join, sync::Barrier, task::AbortHandle};
27
34
 
28
35
  static ANY_PORT: &str = "127.0.0.1:0";
29
36
 
@@ -31,15 +38,41 @@ async fn get_text(endpoint: String) -> String {
31
38
  reqwest::get(endpoint).await.unwrap().text().await.unwrap()
32
39
  }
33
40
 
41
+ struct AbortOnDrop {
42
+ ah: AbortHandle,
43
+ }
44
+ impl Drop for AbortOnDrop {
45
+ fn drop(&mut self) {
46
+ self.ah.abort();
47
+ }
48
+ }
49
+
50
+ fn prom_metrics() -> (TelemetryOptions, SocketAddr, AbortOnDrop) {
51
+ let mut telemopts = get_integ_telem_options();
52
+ let prom_info = start_prometheus_metric_exporter(
53
+ PrometheusExporterOptionsBuilder::default()
54
+ .socket_addr(ANY_PORT.parse().unwrap())
55
+ .build()
56
+ .unwrap(),
57
+ )
58
+ .unwrap();
59
+ telemopts.metrics = Some(prom_info.meter as Arc<dyn CoreMeter>);
60
+ (
61
+ telemopts,
62
+ prom_info.bound_addr,
63
+ AbortOnDrop {
64
+ ah: prom_info.abort_handle,
65
+ },
66
+ )
67
+ }
68
+
34
69
  #[tokio::test]
35
70
  async fn prometheus_metrics_exported() {
36
- let mut telemopts = get_integ_telem_options();
37
- telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
71
+ let (telemopts, addr, _aborter) = prom_metrics();
38
72
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
39
- let addr = rt.telemetry().prom_port().unwrap();
40
73
  let opts = get_integ_server_options();
41
74
  let mut raw_client = opts
42
- .connect_no_namespace(rt.metric_meter().as_deref(), None)
75
+ .connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
43
76
  .await
44
77
  .unwrap();
45
78
  assert!(raw_client.get_client().capabilities().is_some());
@@ -56,15 +89,26 @@ async fn prometheus_metrics_exported() {
56
89
  assert!(body.contains(
57
90
  "temporal_request_latency_count{operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\"} 1"
58
91
  ));
92
+ // Verify counter names are appropriate (don't end w/ '_total')
93
+ assert!(body.contains("temporal_request{"));
94
+ // Verify non-temporal metrics meter does not prefix
95
+ let mm = rt.telemetry().get_metric_meter().unwrap();
96
+ let g = mm.inner.gauge(MetricParameters::from("mygauge"));
97
+ g.record(
98
+ 42,
99
+ &MetricAttributes::OTel {
100
+ kvs: Arc::new(vec![]),
101
+ },
102
+ );
103
+ let body = get_text(format!("http://{addr}/metrics")).await;
104
+ assert!(body.contains("\nmygauge 42"));
59
105
  }
60
106
 
61
107
  #[tokio::test]
62
108
  async fn one_slot_worker_reports_available_slot() {
63
- let mut telemopts = get_integ_telem_options();
109
+ let (telemopts, addr, _aborter) = prom_metrics();
64
110
  let tq = "one_slot_worker_tq";
65
- telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
66
111
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
67
- let addr = rt.telemetry().prom_port().unwrap();
68
112
 
69
113
  let worker_cfg = WorkerConfigBuilder::default()
70
114
  .namespace(NAMESPACE)
@@ -161,6 +205,16 @@ async fn one_slot_worker_reports_available_slot() {
161
205
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
162
206
  worker_type=\"WorkflowWorker\"}} 2"
163
207
  )));
208
+ assert!(body.contains(&format!(
209
+ "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
210
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
211
+ worker_type=\"ActivityWorker\"}} 1"
212
+ )));
213
+ assert!(body.contains(&format!(
214
+ "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
215
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
216
+ worker_type=\"LocalActivityWorker\"}} 1"
217
+ )));
164
218
 
165
219
  // Start a workflow so that a task will get delivered
166
220
  client
@@ -182,7 +236,7 @@ async fn one_slot_worker_reports_available_slot() {
182
236
  wf_task_barr.wait().await;
183
237
 
184
238
  // At this point the workflow task is outstanding, so there should be 0 slots, and
185
- // the activities haven't started, so there should be 1 each.
239
+ // the activities haven't started, so there should still be 1 each.
186
240
  let body = get_text(format!("http://{addr}/metrics")).await;
187
241
  assert!(body.contains(&format!(
188
242
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
@@ -264,10 +318,8 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
264
318
  )]
265
319
  completion: workflow_command::Variant,
266
320
  ) {
267
- let mut telemopts = get_integ_telem_options();
268
- telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
321
+ let (telemopts, addr, _aborter) = prom_metrics();
269
322
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
270
- let addr = rt.telemetry().prom_port().unwrap();
271
323
  let mut starter =
272
324
  CoreWfStarter::new_with_runtime("query_of_closed_workflow_doesnt_tick_terminal_metric", rt);
273
325
  // Disable cache to ensure replay happens completely
@@ -275,7 +327,22 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
275
327
  let worker = starter.get_worker().await;
276
328
  let run_id = starter.start_wf().await;
277
329
  let task = worker.poll_workflow_activation().await.unwrap();
330
+ // Fail wf task
331
+ worker
332
+ .complete_workflow_activation(WorkflowActivationCompletion::fail(
333
+ task.run_id,
334
+ "whatever".into(),
335
+ ))
336
+ .await
337
+ .unwrap();
338
+ // Handle cache eviction
339
+ let task = worker.poll_workflow_activation().await.unwrap();
340
+ worker
341
+ .complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
342
+ .await
343
+ .unwrap();
278
344
  // Immediately complete the workflow
345
+ let task = worker.poll_workflow_activation().await.unwrap();
279
346
  worker
280
347
  .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
281
348
  task.run_id,
@@ -370,3 +437,31 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
370
437
  .expect("Must find matching metric");
371
438
  assert!(matching_line.ends_with('1'));
372
439
  }
440
+
441
+ #[test]
442
+ fn runtime_new() {
443
+ let mut rt = CoreRuntime::new(
444
+ get_integ_telem_options(),
445
+ tokio::runtime::Builder::new_multi_thread(),
446
+ )
447
+ .unwrap();
448
+ let handle = rt.tokio_handle();
449
+ let _rt = handle.enter();
450
+ let (telemopts, addr, _aborter) = prom_metrics();
451
+ rt.telemetry_mut()
452
+ .attach_late_init_metrics(telemopts.metrics.unwrap());
453
+ let opts = get_integ_server_options();
454
+ handle.block_on(async {
455
+ let mut raw_client = opts
456
+ .connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
457
+ .await
458
+ .unwrap();
459
+ assert!(raw_client.get_client().capabilities().is_some());
460
+ let _ = raw_client
461
+ .list_namespaces(ListNamespacesRequest::default())
462
+ .await
463
+ .unwrap();
464
+ let body = get_text(format!("http://{addr}/metrics")).await;
465
+ assert!(body.contains("temporal_request"));
466
+ });
467
+ }
@@ -1,6 +1,7 @@
1
1
  use assert_matches::assert_matches;
2
2
  use futures::{prelude::stream::FuturesUnordered, FutureExt, StreamExt};
3
- use std::time::Duration;
3
+ use futures_util::future::join_all;
4
+ use std::time::{Duration, Instant};
4
5
  use temporal_client::WorkflowClientTrait;
5
6
  use temporal_sdk_core_protos::{
6
7
  coresdk::{
@@ -13,6 +14,7 @@ use temporal_sdk_core_protos::{
13
14
  use temporal_sdk_core_test_utils::{
14
15
  drain_pollers_and_shutdown, init_core_and_create_wf, WorkerTestHelpers,
15
16
  };
17
+ use tokio::join;
16
18
 
17
19
  #[tokio::test]
18
20
  async fn simple_query_legacy() {
@@ -102,7 +104,7 @@ async fn simple_query_legacy() {
102
104
  let task = core.poll_workflow_activation().await.unwrap();
103
105
  core.complete_execution(&task.run_id).await;
104
106
  };
105
- let (q_resp, _) = tokio::join!(query_fut, workflow_completions_future);
107
+ let (q_resp, _) = join!(query_fut, workflow_completions_future);
106
108
  // Ensure query response is as expected
107
109
  assert_eq!(&q_resp.unwrap()[0].data, query_resp);
108
110
  }
@@ -308,7 +310,176 @@ async fn fail_legacy_query() {
308
310
  let task = core.poll_workflow_activation().await.unwrap();
309
311
  core.complete_execution(&task.run_id).await;
310
312
  };
311
- let (q_resp, _) = tokio::join!(query_fut, workflow_completions_future);
313
+ let (q_resp, _) = join!(query_fut, workflow_completions_future);
312
314
  // Ensure query response is a failure and has the right message
313
315
  assert_eq!(q_resp.message(), query_err);
314
316
  }
317
+
318
+ #[tokio::test]
319
+ async fn multiple_concurrent_queries_no_new_history() {
320
+ let mut starter = init_core_and_create_wf("multiple_concurrent_queries_no_new_history").await;
321
+ let core = starter.get_worker().await;
322
+ let workflow_id = starter.get_task_queue().to_string();
323
+ let started = Instant::now();
324
+ let task = core.poll_workflow_activation().await.unwrap();
325
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
326
+ task.run_id.clone(),
327
+ vec![], // complete with no commands so that there will be no new history
328
+ ))
329
+ .await
330
+ .unwrap();
331
+ let client = starter.get_client().await;
332
+ let num_queries = 10;
333
+ let query_futs = (1..=num_queries).map(|_| async {
334
+ client
335
+ .query_workflow_execution(
336
+ workflow_id.to_string(),
337
+ task.run_id.to_string(),
338
+ WorkflowQuery {
339
+ query_type: "myquery".to_string(),
340
+ query_args: Some(b"hi".into()),
341
+ header: None,
342
+ },
343
+ )
344
+ .await
345
+ .unwrap();
346
+ });
347
+ let complete_fut = async {
348
+ for _ in 1..=num_queries {
349
+ let task = core.poll_workflow_activation().await.unwrap();
350
+ let query = assert_matches!(
351
+ task.jobs.as_slice(),
352
+ [WorkflowActivationJob {
353
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
354
+ }] => q
355
+ );
356
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
357
+ task.run_id,
358
+ QueryResult {
359
+ query_id: query.query_id.clone(),
360
+ variant: Some(
361
+ QuerySuccess {
362
+ response: Some("done".into()),
363
+ }
364
+ .into(),
365
+ ),
366
+ }
367
+ .into(),
368
+ ))
369
+ .await
370
+ .unwrap();
371
+ }
372
+ };
373
+ join!(join_all(query_futs), complete_fut);
374
+ // No need to properly finish
375
+ client
376
+ .terminate_workflow_execution(workflow_id, None)
377
+ .await
378
+ .unwrap();
379
+ // This test should not take a long time. Things can still work, but if it takes a long time
380
+ // that means we aren't buffering properly, and tasks are getting redelivered after timeout.
381
+ if started.elapsed() > Duration::from_secs(9) {
382
+ panic!("Should not have taken this long");
383
+ }
384
+ }
385
+
386
+ #[tokio::test]
387
+ async fn query_superseded_by_newer_wft_is_discarded() {
388
+ let mut starter = init_core_and_create_wf("query_superseded_by_newer_wft_is_discarded").await;
389
+ let core = starter.get_worker().await;
390
+ let workflow_id = starter.get_task_queue().to_string();
391
+ let task = core.poll_workflow_activation().await.unwrap();
392
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
393
+ task.run_id.clone(),
394
+ vec![], // complete with no commands so that there will be no new history
395
+ ))
396
+ .await
397
+ .unwrap();
398
+ let client = starter.get_client().await;
399
+ // Send two queries so that one of them is buffered
400
+ let query_futs = (1..=2).map(|_| async {
401
+ client
402
+ .query_workflow_execution(
403
+ workflow_id.to_string(),
404
+ task.run_id.to_string(),
405
+ WorkflowQuery {
406
+ query_type: "myquery".to_string(),
407
+ query_args: Some(b"hi".into()),
408
+ header: None,
409
+ },
410
+ )
411
+ .await
412
+ .unwrap();
413
+ });
414
+ let complete_fut = async {
415
+ let task = core.poll_workflow_activation().await.unwrap();
416
+ let query = assert_matches!(
417
+ task.jobs.as_slice(),
418
+ [WorkflowActivationJob {
419
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
420
+ }] => q
421
+ );
422
+ // While handling the first query, signal the workflow so a new WFT is generated and the
423
+ // second query is still in the buffer
424
+ client
425
+ .signal_workflow_execution(
426
+ workflow_id.to_string(),
427
+ task.run_id.to_string(),
428
+ "blah".to_string(),
429
+ None,
430
+ None,
431
+ )
432
+ .await
433
+ .unwrap();
434
+ tokio::time::sleep(Duration::from_millis(500)).await;
435
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
436
+ task.run_id,
437
+ QueryResult {
438
+ query_id: query.query_id.clone(),
439
+ variant: Some(
440
+ QuerySuccess {
441
+ response: Some("done".into()),
442
+ }
443
+ .into(),
444
+ ),
445
+ }
446
+ .into(),
447
+ ))
448
+ .await
449
+ .unwrap();
450
+ // We should get the signal activation since the in-buffer query should've been failed
451
+ let task = core.poll_workflow_activation().await.unwrap();
452
+ assert_matches!(
453
+ task.jobs.as_slice(),
454
+ [WorkflowActivationJob {
455
+ variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
456
+ }]
457
+ );
458
+ core.complete_execution(&task.run_id).await;
459
+ // Query will get retried by server since we fail the task w/ the stale query
460
+ let task = core.poll_workflow_activation().await.unwrap();
461
+ let query = assert_matches!(
462
+ task.jobs.as_slice(),
463
+ [WorkflowActivationJob {
464
+ variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
465
+ }] => q
466
+ );
467
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
468
+ task.run_id,
469
+ QueryResult {
470
+ query_id: query.query_id.clone(),
471
+ variant: Some(
472
+ QuerySuccess {
473
+ response: Some("done".into()),
474
+ }
475
+ .into(),
476
+ ),
477
+ }
478
+ .into(),
479
+ ))
480
+ .await
481
+ .unwrap();
482
+ };
483
+ join!(join_all(query_futs), complete_fut);
484
+ drain_pollers_and_shutdown(&core).await;
485
+ }