@temporalio/core-bridge 1.13.0 → 1.13.2

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 (181) hide show
  1. package/Cargo.lock +239 -382
  2. package/Cargo.toml +11 -11
  3. package/lib/native.d.ts +10 -3
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.cargo/config.toml +71 -11
  11. package/sdk-core/.clippy.toml +1 -0
  12. package/sdk-core/.github/workflows/heavy.yml +2 -0
  13. package/sdk-core/.github/workflows/per-pr.yml +50 -18
  14. package/sdk-core/ARCHITECTURE.md +44 -48
  15. package/sdk-core/Cargo.toml +26 -7
  16. package/sdk-core/README.md +4 -0
  17. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  18. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  19. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  20. package/sdk-core/client/Cargo.toml +8 -7
  21. package/sdk-core/client/src/callback_based.rs +1 -2
  22. package/sdk-core/client/src/lib.rs +485 -299
  23. package/sdk-core/client/src/metrics.rs +32 -8
  24. package/sdk-core/client/src/proxy.rs +124 -5
  25. package/sdk-core/client/src/raw.rs +598 -307
  26. package/sdk-core/client/src/replaceable.rs +253 -0
  27. package/sdk-core/client/src/retry.rs +9 -6
  28. package/sdk-core/client/src/worker_registry/mod.rs +19 -3
  29. package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
  30. package/sdk-core/core/Cargo.toml +100 -31
  31. package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
  32. package/sdk-core/core/src/core_tests/mod.rs +2 -8
  33. package/sdk-core/core/src/core_tests/queries.rs +3 -5
  34. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
  35. package/sdk-core/core/src/core_tests/updates.rs +4 -5
  36. package/sdk-core/core/src/core_tests/workers.rs +4 -3
  37. package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
  38. package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
  39. package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
  40. package/sdk-core/core/src/internal_flags.rs +11 -1
  41. package/sdk-core/core/src/lib.rs +50 -36
  42. package/sdk-core/core/src/pollers/mod.rs +5 -5
  43. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  44. package/sdk-core/core/src/protosext/mod.rs +13 -5
  45. package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
  46. package/sdk-core/core/src/retry_logic.rs +256 -108
  47. package/sdk-core/core/src/telemetry/metrics.rs +1 -0
  48. package/sdk-core/core/src/telemetry/mod.rs +8 -2
  49. package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
  50. package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
  51. package/sdk-core/core/src/test_help/mod.rs +10 -1100
  52. package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
  53. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
  55. package/sdk-core/core/src/worker/activities.rs +10 -3
  56. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  57. package/sdk-core/core/src/worker/client.rs +130 -93
  58. package/sdk-core/core/src/worker/heartbeat.rs +12 -13
  59. package/sdk-core/core/src/worker/mod.rs +31 -21
  60. package/sdk-core/core/src/worker/nexus.rs +14 -3
  61. package/sdk-core/core/src/worker/slot_provider.rs +9 -0
  62. package/sdk-core/core/src/worker/tuner.rs +159 -0
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
  64. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
  65. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
  66. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
  67. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
  68. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
  69. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
  71. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
  72. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
  73. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
  74. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
  75. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
  76. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
  77. package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
  78. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
  79. package/sdk-core/core-api/Cargo.toml +4 -4
  80. package/sdk-core/core-api/src/envconfig.rs +153 -54
  81. package/sdk-core/core-api/src/lib.rs +68 -0
  82. package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
  83. package/sdk-core/core-api/src/telemetry.rs +13 -0
  84. package/sdk-core/core-c-bridge/Cargo.toml +13 -8
  85. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
  86. package/sdk-core/core-c-bridge/src/client.rs +462 -184
  87. package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
  88. package/sdk-core/core-c-bridge/src/lib.rs +1 -0
  89. package/sdk-core/core-c-bridge/src/random.rs +4 -4
  90. package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
  91. package/sdk-core/core-c-bridge/src/testing.rs +1 -4
  92. package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
  93. package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
  94. package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
  95. package/sdk-core/core-c-bridge/src/worker.rs +319 -66
  96. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
  98. package/sdk-core/sdk/Cargo.toml +8 -2
  99. package/sdk-core/sdk/src/activity_context.rs +1 -1
  100. package/sdk-core/sdk/src/app_data.rs +1 -1
  101. package/sdk-core/sdk/src/interceptors.rs +1 -4
  102. package/sdk-core/sdk/src/lib.rs +1 -5
  103. package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
  104. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  105. package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
  106. package/sdk-core/sdk-core-protos/build.rs +10 -23
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  116. package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
  117. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
  118. package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
  119. package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
  120. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
  121. package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  122. package/sdk-core/tests/cloud_tests.rs +10 -8
  123. package/sdk-core/tests/common/http_proxy.rs +134 -0
  124. package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
  125. package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
  126. package/sdk-core/tests/fuzzy_workflow.rs +1 -1
  127. package/sdk-core/tests/global_metric_tests.rs +8 -7
  128. package/sdk-core/tests/heavy_tests.rs +7 -3
  129. package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
  130. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
  131. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
  132. package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
  133. package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  134. package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
  135. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  136. package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
  137. package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
  138. package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
  139. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
  140. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
  141. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
  144. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
  145. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
  146. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
  147. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  148. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
  149. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
  150. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
  151. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
  152. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
  153. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
  154. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
  155. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
  156. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
  157. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
  158. package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
  159. package/sdk-core/tests/main.rs +26 -17
  160. package/sdk-core/tests/manual_tests.rs +5 -1
  161. package/sdk-core/tests/runner.rs +22 -40
  162. package/sdk-core/tests/shared_tests/mod.rs +1 -1
  163. package/sdk-core/tests/shared_tests/priority.rs +1 -1
  164. package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
  165. package/src/client.rs +97 -20
  166. package/src/helpers/callbacks.rs +4 -4
  167. package/src/helpers/errors.rs +7 -1
  168. package/src/helpers/handles.rs +1 -0
  169. package/src/helpers/try_from_js.rs +4 -3
  170. package/src/lib.rs +3 -2
  171. package/src/metrics.rs +3 -0
  172. package/src/runtime.rs +5 -2
  173. package/src/worker.rs +9 -12
  174. package/ts/native.ts +13 -3
  175. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  176. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  177. package/sdk-core/core/src/core_tests/determinism.rs +0 -318
  178. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  179. package/sdk-core/test-utils/Cargo.toml +0 -38
  180. package/sdk-core/test-utils/src/histfetch.rs +0 -28
  181. package/sdk-core/test-utils/src/interceptors.rs +0 -46
@@ -1,9 +1,10 @@
1
- use crate::prost_dur;
2
1
  use std::time::Duration;
3
2
  use temporal_sdk::{ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
4
- use temporal_sdk_core_protos::{coresdk::AsJsonPayloadExt, temporal::api::common::v1::RetryPolicy};
3
+ use temporal_sdk_core_protos::{
4
+ coresdk::AsJsonPayloadExt, prost_dur, temporal::api::common::v1::RetryPolicy,
5
+ };
5
6
 
6
- pub async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
7
+ pub(crate) async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
7
8
  ctx.local_activity(LocalActivityOptions {
8
9
  activity_type: "delay".to_string(),
9
10
  input: "hi".as_json_payload().expect("serializes fine"),
@@ -1,3 +1,4 @@
1
+ use crate::common::CoreWfStarter;
1
2
  use futures_util::{FutureExt, StreamExt, sink, stream::FuturesUnordered};
2
3
  use rand::{Rng, SeedableRng, prelude::Distribution, rngs::SmallRng};
3
4
  use std::{future, time::Duration};
@@ -6,7 +7,6 @@ use temporal_sdk::{
6
7
  ActContext, ActivityError, ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult,
7
8
  };
8
9
  use temporal_sdk_core_protos::coresdk::{AsJsonPayloadExt, FromJsonPayloadExt, IntoPayloadsExt};
9
- use temporal_sdk_core_test_utils::CoreWfStarter;
10
10
  use tokio_util::sync::CancellationToken;
11
11
 
12
12
  const FUZZY_SIG: &str = "fuzzy_sig";
@@ -1,3 +1,8 @@
1
+ // All non-main.rs tests ignore dead common code so that the linter doesn't complain about about it.
2
+ #[allow(dead_code)]
3
+ mod common;
4
+
5
+ use common::CoreWfStarter;
1
6
  use parking_lot::Mutex;
2
7
  use std::{sync::Arc, time::Duration};
3
8
  use temporal_sdk_core::{
@@ -7,7 +12,6 @@ use temporal_sdk_core::{
7
12
  use temporal_sdk_core_api::telemetry::{
8
13
  Logger, OtelCollectorOptionsBuilder, TelemetryOptionsBuilder, metrics::CoreMeter,
9
14
  };
10
- use temporal_sdk_core_test_utils::CoreWfStarter;
11
15
  use tracing::Level;
12
16
  use tracing_subscriber::fmt::MakeWriter;
13
17
 
@@ -99,18 +103,15 @@ async fn otel_errors_logged_as_errors() {
99
103
  );
100
104
  assert!(
101
105
  log_str.contains("@@@@@@@@@"),
102
- "Expected fallback log not found in logs: {}",
103
- log_str
106
+ "Expected fallback log not found in logs: {log_str}",
104
107
  );
105
108
  // TODO: OTel just doesn't actually log useful errors right now 🤷, see issues at top of test
106
109
  assert!(
107
110
  log_str.contains("ERROR"),
108
- "Expected ERROR log not found in logs: {}",
109
- log_str
111
+ "Expected ERROR log not found in logs: {log_str}",
110
112
  );
111
113
  assert!(
112
114
  log_str.contains("Metrics exporter otlp failed with the grpc server returns error"),
113
- "Expected an OTel exporter error message in logs: {}",
114
- log_str
115
+ "Expected an OTel exporter error message in logs: {log_str}",
115
116
  );
116
117
  }
@@ -1,3 +1,10 @@
1
+ // All non-main.rs tests ignore dead common code so that the linter doesn't complain about about it.
2
+ #[allow(dead_code)]
3
+ mod common;
4
+
5
+ use common::{
6
+ CoreWfStarter, init_integ_telem, prom_metrics, rand_6_chars, workflows::la_problem_workflow,
7
+ };
1
8
  use futures_util::{
2
9
  StreamExt,
3
10
  future::{AbortHandle, Abortable, join_all},
@@ -18,9 +25,6 @@ use temporal_sdk_core_protos::{
18
25
  coresdk::{AsJsonPayloadExt, workflow_commands::ActivityCancellationType},
19
26
  temporal::api::enums::v1::WorkflowIdReusePolicy,
20
27
  };
21
- use temporal_sdk_core_test_utils::{
22
- CoreWfStarter, init_integ_telem, prom_metrics, rand_6_chars, workflows::la_problem_workflow,
23
- };
24
28
 
25
29
  mod fuzzy_workflow;
26
30
 
@@ -1,3 +1,4 @@
1
+ use crate::common::{CoreWfStarter, NAMESPACE, get_integ_server_options, http_proxy::HttpProxy};
1
2
  use assert_matches::assert_matches;
2
3
  use futures_util::{FutureExt, future::BoxFuture};
3
4
  use http_body_util::Full;
@@ -14,7 +15,8 @@ use std::{
14
15
  time::Duration,
15
16
  };
16
17
  use temporal_client::{
17
- Namespace, RETRYABLE_ERROR_CODES, RetryConfig, WorkflowClientTrait, WorkflowService,
18
+ HttpConnectProxyOptions, Namespace, RETRYABLE_ERROR_CODES, RetryConfig, WorkflowClientTrait,
19
+ WorkflowService,
18
20
  };
19
21
  use temporal_sdk_core_protos::temporal::api::{
20
22
  cloud::cloudservice::v1::GetNamespaceRequest,
@@ -23,13 +25,14 @@ use temporal_sdk_core_protos::temporal::api::{
23
25
  RespondActivityTaskCanceledResponse,
24
26
  },
25
27
  };
26
- use temporal_sdk_core_test_utils::{CoreWfStarter, NAMESPACE, get_integ_server_options};
28
+ #[cfg(unix)]
29
+ use tokio::net::UnixListener;
27
30
  use tokio::{
28
31
  net::TcpListener,
29
32
  sync::{mpsc::UnboundedSender, oneshot},
30
33
  };
31
34
  use tonic::{
32
- Code, Request, Status,
35
+ Code, IntoRequest, Request, Status,
33
36
  body::Body,
34
37
  codegen::{Service, http::Response},
35
38
  server::NamedService,
@@ -53,10 +56,13 @@ async fn can_use_retry_raw_client() {
53
56
  let opts = get_integ_server_options();
54
57
  let mut client = opts.connect_no_namespace(None).await.unwrap();
55
58
  client
56
- .describe_namespace(DescribeNamespaceRequest {
57
- namespace: NAMESPACE.to_string(),
58
- ..Default::default()
59
- })
59
+ .describe_namespace(
60
+ DescribeNamespaceRequest {
61
+ namespace: NAMESPACE.to_string(),
62
+ ..Default::default()
63
+ }
64
+ .into_request(),
65
+ )
60
66
  .await
61
67
  .unwrap();
62
68
  }
@@ -74,12 +80,15 @@ async fn per_call_timeout_respected_whole_client() {
74
80
  let mut raw_client = opts.connect_no_namespace(None).await.unwrap();
75
81
  let mut hm = HashMap::new();
76
82
  hm.insert("grpc-timeout".to_string(), "0S".to_string());
77
- raw_client.get_client().set_headers(hm);
83
+ raw_client.get_client().set_headers(hm).unwrap();
78
84
  let err = raw_client
79
- .describe_namespace(DescribeNamespaceRequest {
80
- namespace: NAMESPACE.to_string(),
81
- ..Default::default()
82
- })
85
+ .describe_namespace(
86
+ DescribeNamespaceRequest {
87
+ namespace: NAMESPACE.to_string(),
88
+ ..Default::default()
89
+ }
90
+ .into_request(),
91
+ )
83
92
  .await
84
93
  .unwrap_err();
85
94
  assert_matches!(err.code(), Code::DeadlineExceeded | Code::Cancelled);
@@ -110,7 +119,7 @@ struct GenericService<F> {
110
119
  }
111
120
  impl<F> Service<tonic::codegen::http::Request<Body>> for GenericService<F>
112
121
  where
113
- F: FnMut() -> BoxFuture<'static, Response<Body>>,
122
+ F: FnMut(tonic::codegen::http::Request<Body>) -> BoxFuture<'static, Response<Body>>,
114
123
  {
115
124
  type Response = Response<Body>;
116
125
  type Error = Infallible;
@@ -132,7 +141,7 @@ where
132
141
  .to_string(),
133
142
  )
134
143
  .unwrap();
135
- let r = (self.response_maker)();
144
+ let r = (self.response_maker)(req);
136
145
  async move { Ok(r.await) }.boxed()
137
146
  }
138
147
  }
@@ -149,7 +158,11 @@ struct FakeServer {
149
158
 
150
159
  async fn fake_server<F>(response_maker: F) -> FakeServer
151
160
  where
152
- F: FnMut() -> BoxFuture<'static, Response<Body>> + Clone + Send + Sync + 'static,
161
+ F: FnMut(tonic::codegen::http::Request<Body>) -> BoxFuture<'static, Response<Body>>
162
+ + Clone
163
+ + Send
164
+ + Sync
165
+ + 'static,
153
166
  {
154
167
  let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
155
168
  let (header_tx, header_rx) = tokio::sync::mpsc::unbounded_channel();
@@ -191,7 +204,7 @@ impl FakeServer {
191
204
 
192
205
  #[tokio::test]
193
206
  async fn timeouts_respected_one_call_fake_server() {
194
- let mut fs = fake_server(|| async { Response::new(Body::empty()) }.boxed()).await;
207
+ let mut fs = fake_server(|_| async { Response::new(Body::empty()) }.boxed()).await;
195
208
  let header_rx = &mut fs.header_rx;
196
209
 
197
210
  let mut opts = get_integ_server_options();
@@ -260,7 +273,7 @@ async fn non_retryable_errors() {
260
273
  Code::Unauthenticated,
261
274
  Code::Unimplemented,
262
275
  ] {
263
- let mut fs = fake_server(move || {
276
+ let mut fs = fake_server(move |_| {
264
277
  let s = Status::new(code, "bla").into_http();
265
278
  async { s }.boxed()
266
279
  })
@@ -295,7 +308,7 @@ async fn retryable_errors() {
295
308
  .filter(|p| p != &Code::ResourceExhausted)
296
309
  {
297
310
  let count = Arc::new(AtomicUsize::new(0));
298
- let mut fs = fake_server(move || {
311
+ let mut fs = fake_server(move |_| {
299
312
  let prev = count.fetch_add(1, Ordering::Relaxed);
300
313
  let r = if prev < 3 {
301
314
  Status::new(code, "bla").into_http()
@@ -339,7 +352,7 @@ async fn namespace_header_attached_to_relevant_calls() {
339
352
  .add_service(GenericService {
340
353
  header_to_parse: "Temporal-Namespace",
341
354
  header_tx,
342
- response_maker: || async { Response::new(Body::empty()) }.boxed(),
355
+ response_maker: |_| async { Response::new(Body::empty()) }.boxed(),
343
356
  })
344
357
  .serve_with_incoming_shutdown(
345
358
  tokio_stream::wrappers::TcpListenerStream::new(listener),
@@ -402,17 +415,91 @@ async fn cloud_ops_test() {
402
415
  hm.insert("temporal-cloud-api-version".to_string(), api_version);
403
416
  hm
404
417
  });
405
- let mut client = opts.connect_no_namespace(None).await.unwrap().into_inner();
406
- let cloud_client = client.cloud_svc_mut();
418
+ let client = opts.connect_no_namespace(None).await.unwrap().into_inner();
419
+ let mut cloud_client = client.cloud_svc();
407
420
  let res = cloud_client
408
- .get_namespace(GetNamespaceRequest {
409
- namespace: namespace.clone(),
410
- })
421
+ .get_namespace(
422
+ GetNamespaceRequest {
423
+ namespace: namespace.clone(),
424
+ }
425
+ .into_request(),
426
+ )
411
427
  .await
412
428
  .unwrap();
413
429
  assert_eq!(res.into_inner().namespace.unwrap().namespace, namespace);
414
430
  }
415
431
 
432
+ #[tokio::test]
433
+ async fn http_proxy() {
434
+ // Create server
435
+ let call_count = Arc::new(AtomicUsize::new(0));
436
+ let call_count_cloned = call_count.clone();
437
+ let server = fake_server(move |_| {
438
+ call_count_cloned.fetch_add(1, Ordering::SeqCst);
439
+ async { Response::new(Body::empty()) }.boxed()
440
+ })
441
+ .await;
442
+
443
+ // Create HTTP TCP proxy
444
+ let tcp_proxy_listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
445
+ let tcp_proxy_addr = tcp_proxy_listener.local_addr().unwrap();
446
+ let tcp_proxy = HttpProxy::spawn_tcp(tcp_proxy_listener);
447
+
448
+ // General client options
449
+ let mut opts = get_integ_server_options();
450
+ opts.retry_config = RetryConfig::no_retries();
451
+ opts.skip_get_system_info = true;
452
+
453
+ // Connect client with no proxy and make call and confirm reached
454
+ opts.target_url = format!("http://127.0.0.1:{}", server.addr.port())
455
+ .parse()
456
+ .unwrap();
457
+ let client = opts.connect("my-namespace", None).await.unwrap();
458
+ let _ = client.list_namespaces().await;
459
+ assert!(call_count.load(Ordering::SeqCst) == 1);
460
+ assert!(tcp_proxy.hit_count() == 0);
461
+
462
+ // Connect client to proxy and make call and confirm reached
463
+ opts.http_connect_proxy = Some(HttpConnectProxyOptions {
464
+ target_addr: tcp_proxy_addr.to_string(),
465
+ basic_auth: None,
466
+ });
467
+ let proxied_client = opts.connect("my-namespace", None).await.unwrap();
468
+ let _ = proxied_client.list_namespaces().await;
469
+ assert!(call_count.load(Ordering::SeqCst) == 2);
470
+ assert!(tcp_proxy.hit_count() == 1);
471
+
472
+ // Test Unix socket too only in Unix environments
473
+ #[cfg(unix)]
474
+ {
475
+ // Create temp socket path
476
+ let mut sock_path = std::env::temp_dir();
477
+ sock_path.push(format!("http-proxy-test-{}.sock", std::process::id()));
478
+ // Remove if there just in case
479
+ let _ = std::fs::remove_file(&sock_path);
480
+
481
+ // Create unix-socket-based proxy
482
+ let unix_proxy = HttpProxy::spawn_unix(UnixListener::bind(&sock_path).unwrap());
483
+
484
+ // Connect client to proxy and make call and confirm reached
485
+ opts.http_connect_proxy = Some(HttpConnectProxyOptions {
486
+ target_addr: format!("unix:{}", sock_path.to_str().unwrap()),
487
+ basic_auth: None,
488
+ });
489
+ let proxied_client = opts.connect("my-namespace", None).await.unwrap();
490
+ let _ = proxied_client.list_namespaces().await;
491
+ assert!(call_count.load(Ordering::SeqCst) == 3);
492
+ assert!(unix_proxy.hit_count() == 1);
493
+
494
+ // Shutdown unix proxy
495
+ unix_proxy.shutdown();
496
+ }
497
+
498
+ // Shutdown server and proxy
499
+ server.shutdown().await;
500
+ tcp_proxy.shutdown();
501
+ }
502
+
416
503
  fn make_ok_response<T>(message: T) -> Response<Body>
417
504
  where
418
505
  T: Message,
@@ -1,11 +1,13 @@
1
+ use crate::common::{INTEG_CLIENT_IDENTITY, INTEG_CLIENT_NAME, INTEG_CLIENT_VERSION, NAMESPACE};
1
2
  use futures_util::{TryStreamExt, stream};
2
3
  use std::time::{SystemTime, UNIX_EPOCH};
3
4
  use temporal_client::{ClientOptionsBuilder, TestService, WorkflowService};
4
5
  use temporal_sdk_core::ephemeral_server::{
5
6
  EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporalDevServerConfigBuilder,
7
+ default_cached_download,
6
8
  };
7
9
  use temporal_sdk_core_protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
8
- use temporal_sdk_core_test_utils::{NAMESPACE, default_cached_download};
10
+ use tonic::IntoRequest;
9
11
  use url::Url;
10
12
 
11
13
  #[tokio::test]
@@ -136,27 +138,30 @@ fn fixed_cached_download(version: &str) -> EphemeralExe {
136
138
  async fn assert_ephemeral_server(server: &EphemeralServer) {
137
139
  // Connect and describe namespace
138
140
  let mut client = ClientOptionsBuilder::default()
139
- .identity("integ_tester".to_string())
141
+ .identity(INTEG_CLIENT_IDENTITY.to_string())
140
142
  .target_url(Url::try_from(&*format!("http://{}", server.target)).unwrap())
141
- .client_name("temporal-core".to_string())
142
- .client_version("0.1.0".to_string())
143
+ .client_name(INTEG_CLIENT_NAME.to_string())
144
+ .client_version(INTEG_CLIENT_VERSION.to_string())
143
145
  .build()
144
146
  .unwrap()
145
147
  .connect_no_namespace(None)
146
148
  .await
147
149
  .unwrap();
148
150
  let resp = client
149
- .describe_namespace(DescribeNamespaceRequest {
150
- namespace: NAMESPACE.to_string(),
151
- ..Default::default()
152
- })
151
+ .describe_namespace(
152
+ DescribeNamespaceRequest {
153
+ namespace: NAMESPACE.to_string(),
154
+ ..Default::default()
155
+ }
156
+ .into_request(),
157
+ )
153
158
  .await
154
159
  .unwrap();
155
160
  assert!(resp.into_inner().namespace_info.unwrap().name == "default");
156
161
 
157
162
  // If it has test service, make sure we can use it too
158
163
  if server.has_test_service {
159
- let resp = client.get_current_time(()).await.unwrap();
164
+ let resp = client.get_current_time(().into_request()).await.unwrap();
160
165
  // Make sure it's within 5 mins of now
161
166
  let resp_seconds = resp.get_ref().time.as_ref().unwrap().seconds as u64;
162
167
  let curr_seconds = SystemTime::now()
@@ -1,7 +1,9 @@
1
+ use crate::common::{CoreWfStarter, init_core_and_create_wf};
1
2
  use assert_matches::assert_matches;
2
3
  use std::time::Duration;
3
4
  use temporal_client::{WfClientExt, WorkflowOptions};
4
5
  use temporal_sdk::{ActContext, ActivityOptions, WfContext};
6
+ use temporal_sdk_core::test_help::{WorkerTestHelpers, drain_pollers_and_shutdown};
5
7
  use temporal_sdk_core_protos::{
6
8
  DEFAULT_ACTIVITY_TYPE,
7
9
  coresdk::{
@@ -14,14 +16,12 @@ use temporal_sdk_core_protos::{
14
16
  workflow_commands::{ActivityCancellationType, ScheduleActivity},
15
17
  workflow_completion::WorkflowActivationCompletion,
16
18
  },
19
+ prost_dur,
17
20
  temporal::api::{
18
21
  common::v1::{Payload, RetryPolicy},
19
22
  enums::v1::TimeoutType,
20
23
  },
21
- };
22
- use temporal_sdk_core_test_utils::{
23
- CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, init_core_and_create_wf,
24
- schedule_activity_cmd,
24
+ test_utils::schedule_activity_cmd,
25
25
  };
26
26
  use tokio::time::sleep;
27
27
 
@@ -1,4 +1,10 @@
1
- use crate::integ_tests::mk_nexus_endpoint;
1
+ use crate::{
2
+ common::{
3
+ ANY_PORT, CoreWfStarter, NAMESPACE, OTEL_URL_ENV_VAR, PROMETHEUS_QUERY_API,
4
+ get_integ_server_options, get_integ_telem_options, prom_metrics,
5
+ },
6
+ integ_tests::mk_nexus_endpoint,
7
+ };
2
8
  use anyhow::anyhow;
3
9
  use assert_matches::assert_matches;
4
10
  use std::{
@@ -24,7 +30,7 @@ use temporal_sdk_core_api::{
24
30
  errors::PollError,
25
31
  telemetry::{
26
32
  HistogramBucketOverrides, OtelCollectorOptionsBuilder, OtlpProtocol,
27
- PrometheusExporterOptionsBuilder, TelemetryOptionsBuilder,
33
+ PrometheusExporterOptionsBuilder, TaskQueueLabelStrategy, TelemetryOptionsBuilder,
28
34
  metrics::{
29
35
  CoreMeter, CounterBase, Gauge, GaugeBase, HistogramBase, MetricKeyValue,
30
36
  MetricParameters, MetricParametersBuilder, NewAttributes,
@@ -49,6 +55,7 @@ use temporal_sdk_core_protos::{
49
55
  },
50
56
  workflow_completion::WorkflowActivationCompletion,
51
57
  },
58
+ prost_dur,
52
59
  temporal::api::{
53
60
  common::v1::RetryPolicy,
54
61
  enums::v1::{NexusHandlerErrorRetryBehavior, WorkflowIdReusePolicy},
@@ -62,11 +69,8 @@ use temporal_sdk_core_protos::{
62
69
  workflowservice::v1::{DescribeNamespaceRequest, ListNamespacesRequest},
63
70
  },
64
71
  };
65
- use temporal_sdk_core_test_utils::{
66
- ANY_PORT, CoreWfStarter, NAMESPACE, OTEL_URL_ENV_VAR, PROMETHEUS_QUERY_API,
67
- get_integ_server_options, get_integ_telem_options, prom_metrics,
68
- };
69
72
  use tokio::{join, sync::Barrier};
73
+ use tonic::IntoRequest;
70
74
  use url::Url;
71
75
 
72
76
  pub(crate) async fn get_text(endpoint: String) -> String {
@@ -103,7 +107,7 @@ async fn prometheus_metrics_exported(
103
107
  assert!(raw_client.get_client().capabilities().is_some());
104
108
 
105
109
  let _ = raw_client
106
- .list_namespaces(ListNamespacesRequest::default())
110
+ .list_namespaces(ListNamespacesRequest::default().into_request())
107
111
  .await
108
112
  .unwrap();
109
113
 
@@ -535,7 +539,7 @@ fn runtime_new() {
535
539
  .unwrap();
536
540
  assert!(raw_client.get_client().capabilities().is_some());
537
541
  let _ = raw_client
538
- .list_namespaces(ListNamespacesRequest::default())
542
+ .list_namespaces(ListNamespacesRequest::default().into_request())
539
543
  .await
540
544
  .unwrap();
541
545
  let body = get_text(format!("http://{addr}/metrics")).await;
@@ -629,9 +633,12 @@ async fn request_fail_codes() {
629
633
  .unwrap();
630
634
 
631
635
  // Describe namespace w/ invalid argument (unset namespace field)
632
- WorkflowService::describe_namespace(&mut client, DescribeNamespaceRequest::default())
633
- .await
634
- .unwrap_err();
636
+ WorkflowService::describe_namespace(
637
+ &mut client,
638
+ DescribeNamespaceRequest::default().into_request(),
639
+ )
640
+ .await
641
+ .unwrap_err();
635
642
 
636
643
  let body = get_text(format!("http://{addr}/metrics")).await;
637
644
  let matching_line = body
@@ -674,9 +681,12 @@ async fn request_fail_codes_otel() {
674
681
 
675
682
  for _ in 0..10 {
676
683
  // Describe namespace w/ invalid argument (unset namespace field)
677
- WorkflowService::describe_namespace(&mut client, DescribeNamespaceRequest::default())
678
- .await
679
- .unwrap_err();
684
+ WorkflowService::describe_namespace(
685
+ &mut client,
686
+ DescribeNamespaceRequest::default().into_request(),
687
+ )
688
+ .await
689
+ .unwrap_err();
680
690
 
681
691
  tokio::time::sleep(Duration::from_secs(1)).await;
682
692
  }
@@ -1313,3 +1323,93 @@ async fn prometheus_label_nonsense() {
1313
1323
  assert!(body.contains("some_counter{thing=\"foo\"} 2"));
1314
1324
  assert!(body.contains("some_counter{blerp=\"baz\"} 2"));
1315
1325
  }
1326
+
1327
+ #[rstest::rstest]
1328
+ #[tokio::test]
1329
+ async fn sticky_queue_label_strategy(
1330
+ #[values(
1331
+ TaskQueueLabelStrategy::UseNormal,
1332
+ TaskQueueLabelStrategy::UseNormalAndSticky
1333
+ )]
1334
+ strategy: TaskQueueLabelStrategy,
1335
+ ) {
1336
+ let (mut telemopts, addr, _aborter) = prom_metrics(Some(
1337
+ PrometheusExporterOptionsBuilder::default()
1338
+ .socket_addr(ANY_PORT.parse().unwrap())
1339
+ .build()
1340
+ .unwrap(),
1341
+ ));
1342
+ telemopts.task_queue_label_strategy = strategy;
1343
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
1344
+ let wf_name = format!("sticky_queue_label_strategy_{strategy:?}");
1345
+ let mut starter = CoreWfStarter::new_with_runtime(&wf_name, rt);
1346
+ // Enable sticky queues by setting a reasonable cache size
1347
+ starter.worker_config.max_cached_workflows(10_usize);
1348
+ starter.worker_config.no_remote_activities(true);
1349
+ let task_queue = starter.get_task_queue().to_owned();
1350
+ let mut worker = starter.worker().await;
1351
+
1352
+ worker.register_wf(wf_name.clone(), |ctx: WfContext| async move {
1353
+ ctx.timer(Duration::from_millis(1)).await;
1354
+ Ok(().into())
1355
+ });
1356
+ worker
1357
+ .submit_wf(
1358
+ wf_name.clone(),
1359
+ wf_name,
1360
+ vec![],
1361
+ WorkflowOptions {
1362
+ enable_eager_workflow_start: false,
1363
+ ..Default::default()
1364
+ },
1365
+ )
1366
+ .await
1367
+ .unwrap();
1368
+ worker.run_until_done().await.unwrap();
1369
+
1370
+ // Give metrics time to be recorded
1371
+ tokio::time::sleep(Duration::from_millis(200)).await;
1372
+
1373
+ let body = get_text(format!("http://{addr}/metrics")).await;
1374
+
1375
+ let poll_metrics: Vec<_> = body
1376
+ .lines()
1377
+ .filter(|l| {
1378
+ l.contains("temporal_long_request")
1379
+ && l.contains("operation=\"PollWorkflowTaskQueue\"")
1380
+ && l.contains(&format!("namespace=\"{NAMESPACE}\""))
1381
+ })
1382
+ .collect();
1383
+
1384
+ assert!(!poll_metrics.is_empty(), "Should have poll metrics");
1385
+
1386
+ match strategy {
1387
+ TaskQueueLabelStrategy::UseNormalAndSticky => {
1388
+ // With UseNormalAndSticky, we should see sticky queue names
1389
+ let has_sticky = poll_metrics.iter().any(|l| {
1390
+ l.contains("task_queue=")
1391
+ && l.contains("WorkflowTask")
1392
+ && !l.contains(&format!("task_queue=\"{task_queue}\""))
1393
+ });
1394
+
1395
+ assert!(
1396
+ has_sticky,
1397
+ "With UseNormalAndSticky, should see sticky queue names in metrics. Metrics:\n{}",
1398
+ poll_metrics.join("\n")
1399
+ );
1400
+ }
1401
+ TaskQueueLabelStrategy::UseNormal => {
1402
+ // With UseNormal, ALL metrics should use the normal queue name
1403
+ for l in &poll_metrics {
1404
+ if l.contains("task_queue=") && l.contains("WorkflowTask") {
1405
+ assert!(
1406
+ l.contains(&format!("task_queue=\"{task_queue}\"")),
1407
+ "With UseNormal, all workflow task_queue labels should use normal name. Found: {}",
1408
+ l
1409
+ );
1410
+ }
1411
+ }
1412
+ }
1413
+ _ => unreachable!("Test only covers UseNormal and UseNormalAndSticky"),
1414
+ }
1415
+ }