@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
@@ -9,8 +9,11 @@ extern crate tracing;
9
9
 
10
10
  pub mod callback_based;
11
11
  mod metrics;
12
- mod proxy;
12
+ /// Visible only for tests
13
+ #[doc(hidden)]
14
+ pub mod proxy;
13
15
  mod raw;
16
+ mod replaceable;
14
17
  mod retry;
15
18
  mod worker_registry;
16
19
  mod workflow_handle;
@@ -21,6 +24,7 @@ pub use crate::{
21
24
  };
22
25
  pub use metrics::{LONG_REQUEST_LATENCY_HISTOGRAM_NAME, REQUEST_LATENCY_HISTOGRAM_NAME};
23
26
  pub use raw::{CloudService, HealthService, OperatorService, TestService, WorkflowService};
27
+ pub use replaceable::SharedReplaceableClient;
24
28
  pub use temporal_sdk_core_protos::temporal::api::{
25
29
  enums::v1::ArchivalState,
26
30
  filter::v1::{StartTimeFilter, StatusFilter, WorkflowExecutionFilter, WorkflowTypeFilter},
@@ -37,7 +41,7 @@ pub use workflow_handle::{
37
41
 
38
42
  use crate::{
39
43
  metrics::{ChannelOrGrpcOverride, GrpcMetricSvc, MetricsContext},
40
- raw::{AttachMetricLabels, sealed::RawClientLike},
44
+ raw::AttachMetricLabels,
41
45
  sealed::WfHandleClient,
42
46
  workflow_handle::UntypedWorkflowHandle,
43
47
  };
@@ -72,11 +76,14 @@ use temporal_sdk_core_protos::{
72
76
  },
73
77
  };
74
78
  use tonic::{
75
- Code,
79
+ Code, IntoRequest,
76
80
  body::Body,
77
81
  client::GrpcService,
78
82
  codegen::InterceptedService,
79
- metadata::{MetadataKey, MetadataMap, MetadataValue},
83
+ metadata::{
84
+ AsciiMetadataKey, AsciiMetadataValue, BinaryMetadataKey, BinaryMetadataValue, MetadataMap,
85
+ MetadataValue,
86
+ },
80
87
  service::Interceptor,
81
88
  transport::{Certificate, Channel, Endpoint, Identity},
82
89
  };
@@ -144,9 +151,20 @@ pub struct ClientOptions {
144
151
  pub keep_alive: Option<ClientKeepAliveConfig>,
145
152
 
146
153
  /// HTTP headers to include on every RPC call.
154
+ ///
155
+ /// These must be valid gRPC metadata keys, and must not be binary metadata keys (ending in
156
+ /// `-bin). To set binary headers, use [ClientOptions::binary_headers]. Invalid header keys or
157
+ /// values will cause an error to be returned when connecting.
147
158
  #[builder(default)]
148
159
  pub headers: Option<HashMap<String, String>>,
149
160
 
161
+ /// HTTP headers to include on every RPC call as binary gRPC metadata (encoded as base64).
162
+ ///
163
+ /// These must be valid binary gRPC metadata keys (and end with a `-bin` suffix). Invalid
164
+ /// header keys will cause an error to be returned when connecting.
165
+ #[builder(default)]
166
+ pub binary_headers: Option<HashMap<String, Vec<u8>>>,
167
+
150
168
  /// API key which is set as the "Authorization" header with "Bearer " prepended. This will only
151
169
  /// be applied if the headers don't already have an "Authorization" header.
152
170
  #[builder(default)]
@@ -320,6 +338,9 @@ pub enum ClientInitError {
320
338
  /// Invalid URI. Configuration error, fatal.
321
339
  #[error("Invalid URI: {0:?}")]
322
340
  InvalidUri(#[from] InvalidUri),
341
+ /// Invalid gRPC metadata headers. Configuration error.
342
+ #[error("Invalid headers: {0}")]
343
+ InvalidHeaders(#[from] InvalidHeaderError),
323
344
  /// Server connection error. Crashing and restarting the worker is likely best.
324
345
  #[error("Server connection error: {0:?}")]
325
346
  TonicTransportError(#[from] tonic::transport::Error),
@@ -329,6 +350,37 @@ pub enum ClientInitError {
329
350
  SystemInfoCallError(tonic::Status),
330
351
  }
331
352
 
353
+ /// Errors thrown when a gRPC metadata header is invalid.
354
+ #[derive(thiserror::Error, Debug)]
355
+ pub enum InvalidHeaderError {
356
+ /// A binary header key was invalid
357
+ #[error("Invalid binary header key '{key}': {source}")]
358
+ InvalidBinaryHeaderKey {
359
+ /// The invalid key
360
+ key: String,
361
+ /// The source error from tonic
362
+ source: tonic::metadata::errors::InvalidMetadataKey,
363
+ },
364
+ /// An ASCII header key was invalid
365
+ #[error("Invalid ASCII header key '{key}': {source}")]
366
+ InvalidAsciiHeaderKey {
367
+ /// The invalid key
368
+ key: String,
369
+ /// The source error from tonic
370
+ source: tonic::metadata::errors::InvalidMetadataKey,
371
+ },
372
+ /// An ASCII header value was invalid
373
+ #[error("Invalid ASCII header value for key '{key}': {source}")]
374
+ InvalidAsciiHeaderValue {
375
+ /// The key
376
+ key: String,
377
+ /// The invalid value
378
+ value: String,
379
+ /// The source error from tonic
380
+ source: tonic::metadata::errors::InvalidMetadataValue,
381
+ },
382
+ }
383
+
332
384
  /// A client with [ClientOptions] attached, which can be passed to initialize workers,
333
385
  /// or can be used directly. Is cheap to clone.
334
386
  #[derive(Clone, Debug)]
@@ -342,9 +394,33 @@ pub struct ConfiguredClient<C> {
342
394
  }
343
395
 
344
396
  impl<C> ConfiguredClient<C> {
345
- /// Set HTTP request headers overwriting previous headers
346
- pub fn set_headers(&self, headers: HashMap<String, String>) {
347
- self.headers.write().user_headers = headers;
397
+ /// Set HTTP request headers overwriting previous headers.
398
+ ///
399
+ /// This will not affect headers set via [ClientOptions::binary_headers].
400
+ ///
401
+ /// # Errors
402
+ ///
403
+ /// Will return an error if any of the provided keys or values are not valid gRPC metadata.
404
+ /// If an error is returned, the previous headers will remain unchanged.
405
+ pub fn set_headers(&self, headers: HashMap<String, String>) -> Result<(), InvalidHeaderError> {
406
+ self.headers.write().user_headers = parse_ascii_headers(headers)?;
407
+ Ok(())
408
+ }
409
+
410
+ /// Set binary HTTP request headers overwriting previous headers.
411
+ ///
412
+ /// This will not affect headers set via [ClientOptions::headers].
413
+ ///
414
+ /// # Errors
415
+ ///
416
+ /// Will return an error if any of the provided keys are not valid gRPC binary metadata keys.
417
+ /// If an error is returned, the previous headers will remain unchanged.
418
+ pub fn set_binary_headers(
419
+ &self,
420
+ binary_headers: HashMap<String, Vec<u8>>,
421
+ ) -> Result<(), InvalidHeaderError> {
422
+ self.headers.write().user_binary_headers = parse_binary_headers(binary_headers)?;
423
+ Ok(())
348
424
  }
349
425
 
350
426
  /// Set API key, overwriting previous
@@ -371,7 +447,8 @@ impl<C> ConfiguredClient<C> {
371
447
 
372
448
  #[derive(Debug)]
373
449
  struct ClientHeaders {
374
- user_headers: HashMap<String, String>,
450
+ user_headers: HashMap<AsciiMetadataKey, AsciiMetadataValue>,
451
+ user_binary_headers: HashMap<BinaryMetadataKey, BinaryMetadataValue>,
375
452
  api_key: Option<String>,
376
453
  }
377
454
 
@@ -380,10 +457,13 @@ impl ClientHeaders {
380
457
  for (key, val) in self.user_headers.iter() {
381
458
  // Only if not already present
382
459
  if !metadata.contains_key(key) {
383
- // Ignore invalid keys/values
384
- if let (Ok(key), Ok(val)) = (MetadataKey::from_str(key), val.parse()) {
385
- metadata.insert(key, val);
386
- }
460
+ metadata.insert(key, val.clone());
461
+ }
462
+ }
463
+ for (key, val) in self.user_binary_headers.iter() {
464
+ // Only if not already present
465
+ if !metadata.contains_key(key) {
466
+ metadata.insert_bin(key, val.clone());
387
467
  }
388
468
  }
389
469
  if let Some(api_key) = &self.api_key {
@@ -433,8 +513,7 @@ impl ClientOptions {
433
513
  pub async fn connect_no_namespace(
434
514
  &self,
435
515
  metrics_meter: Option<TemporalMeter>,
436
- ) -> Result<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>, ClientInitError>
437
- {
516
+ ) -> Result<RetryClient<ConfiguredClient<TemporalServiceClient>>, ClientInitError> {
438
517
  self.connect_no_namespace_with_service_override(metrics_meter, None)
439
518
  .await
440
519
  }
@@ -449,8 +528,7 @@ impl ClientOptions {
449
528
  &self,
450
529
  metrics_meter: Option<TemporalMeter>,
451
530
  service_override: Option<callback_based::CallbackBasedGrpcService>,
452
- ) -> Result<RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>, ClientInitError>
453
- {
531
+ ) -> Result<RetryClient<ConfiguredClient<TemporalServiceClient>>, ClientInitError> {
454
532
  let service = if let Some(service_override) = service_override {
455
533
  GrpcMetricSvc {
456
534
  inner: ChannelOrGrpcOverride::GrpcOverride(service_override),
@@ -489,7 +567,10 @@ impl ClientOptions {
489
567
  };
490
568
 
491
569
  let headers = Arc::new(RwLock::new(ClientHeaders {
492
- user_headers: self.headers.clone().unwrap_or_default(),
570
+ user_headers: parse_ascii_headers(self.headers.clone().unwrap_or_default())?,
571
+ user_binary_headers: parse_binary_headers(
572
+ self.binary_headers.clone().unwrap_or_default(),
573
+ )?,
493
574
  api_key: self.api_key.clone(),
494
575
  }));
495
576
  let interceptor = ServiceCallInterceptor {
@@ -507,7 +588,7 @@ impl ClientOptions {
507
588
  };
508
589
  if !self.skip_get_system_info {
509
590
  match client
510
- .get_system_info(GetSystemInfoRequest::default())
591
+ .get_system_info(GetSystemInfoRequest::default().into_request())
511
592
  .await
512
593
  {
513
594
  Ok(sysinfo) => {
@@ -526,11 +607,13 @@ impl ClientOptions {
526
607
  /// Passes it through if TLS options not set.
527
608
  async fn add_tls_to_channel(&self, mut channel: Endpoint) -> Result<Endpoint, ClientInitError> {
528
609
  if let Some(tls_cfg) = &self.tls_cfg {
529
- let mut tls = tonic::transport::ClientTlsConfig::new().with_native_roots();
610
+ let mut tls = tonic::transport::ClientTlsConfig::new();
530
611
 
531
612
  if let Some(root_cert) = &tls_cfg.server_root_ca_cert {
532
613
  let server_root_ca_cert = Certificate::from_pem(root_cert);
533
614
  tls = tls.ca_certificate(server_root_ca_cert);
615
+ } else {
616
+ tls = tls.with_native_roots();
534
617
  }
535
618
 
536
619
  if let Some(domain) = &tls_cfg.domain {
@@ -556,6 +639,57 @@ impl ClientOptions {
556
639
  }
557
640
  }
558
641
 
642
+ fn parse_ascii_headers(
643
+ headers: HashMap<String, String>,
644
+ ) -> Result<HashMap<AsciiMetadataKey, AsciiMetadataValue>, InvalidHeaderError> {
645
+ let mut parsed_headers = HashMap::with_capacity(headers.len());
646
+ for (k, v) in headers.into_iter() {
647
+ let key = match AsciiMetadataKey::from_str(&k) {
648
+ Ok(key) => key,
649
+ Err(err) => {
650
+ return Err(InvalidHeaderError::InvalidAsciiHeaderKey {
651
+ key: k,
652
+ source: err,
653
+ });
654
+ }
655
+ };
656
+ let value = match MetadataValue::from_str(&v) {
657
+ Ok(value) => value,
658
+ Err(err) => {
659
+ return Err(InvalidHeaderError::InvalidAsciiHeaderValue {
660
+ key: k,
661
+ value: v,
662
+ source: err,
663
+ });
664
+ }
665
+ };
666
+ parsed_headers.insert(key, value);
667
+ }
668
+
669
+ Ok(parsed_headers)
670
+ }
671
+
672
+ fn parse_binary_headers(
673
+ headers: HashMap<String, Vec<u8>>,
674
+ ) -> Result<HashMap<BinaryMetadataKey, BinaryMetadataValue>, InvalidHeaderError> {
675
+ let mut parsed_headers = HashMap::with_capacity(headers.len());
676
+ for (k, v) in headers.into_iter() {
677
+ let key = match BinaryMetadataKey::from_str(&k) {
678
+ Ok(key) => key,
679
+ Err(err) => {
680
+ return Err(InvalidHeaderError::InvalidBinaryHeaderKey {
681
+ key: k,
682
+ source: err,
683
+ });
684
+ }
685
+ };
686
+ let value = BinaryMetadataValue::from_bytes(&v);
687
+ parsed_headers.insert(key, value);
688
+ }
689
+
690
+ Ok(parsed_headers)
691
+ }
692
+
559
693
  /// Interceptor which attaches common metadata (like "client-name") to every outgoing call
560
694
  #[derive(Clone)]
561
695
  pub struct ServiceCallInterceptor {
@@ -598,14 +732,13 @@ impl Interceptor for ServiceCallInterceptor {
598
732
  }
599
733
 
600
734
  /// Aggregates various services exposed by the Temporal server
601
- #[derive(Debug, Clone)]
602
- pub struct TemporalServiceClient<T> {
603
- svc: T,
604
- workflow_svc_client: OnceLock<WorkflowServiceClient<T>>,
605
- operator_svc_client: OnceLock<OperatorServiceClient<T>>,
606
- cloud_svc_client: OnceLock<CloudServiceClient<T>>,
607
- test_svc_client: OnceLock<TestServiceClient<T>>,
608
- health_svc_client: OnceLock<HealthClient<T>>,
735
+ #[derive(Clone)]
736
+ pub struct TemporalServiceClient {
737
+ workflow_svc_client: Box<dyn WorkflowService>,
738
+ operator_svc_client: Box<dyn OperatorService>,
739
+ cloud_svc_client: Box<dyn CloudService>,
740
+ test_svc_client: Box<dyn TestService>,
741
+ health_svc_client: Box<dyn HealthService>,
609
742
  }
610
743
 
611
744
  /// We up the limit on incoming messages from server from the 4Mb default to 128Mb. If for
@@ -620,136 +753,100 @@ fn get_decode_max_size() -> usize {
620
753
  })
621
754
  }
622
755
 
623
- impl<T> TemporalServiceClient<T>
624
- where
625
- T: Clone,
626
- T: GrpcService<Body> + Send + Clone + 'static,
627
- T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
628
- T::Error: Into<tonic::codegen::StdError>,
629
- <T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
630
- {
631
- fn new(svc: T) -> Self {
756
+ impl TemporalServiceClient {
757
+ fn new<T>(svc: T) -> Self
758
+ where
759
+ T: GrpcService<Body> + Send + Sync + Clone + 'static,
760
+ T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
761
+ T::Error: Into<tonic::codegen::StdError>,
762
+ <T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
763
+ <T as GrpcService<Body>>::Future: Send,
764
+ {
765
+ let workflow_svc_client = Box::new(
766
+ WorkflowServiceClient::new(svc.clone())
767
+ .max_decoding_message_size(get_decode_max_size()),
768
+ );
769
+ let operator_svc_client = Box::new(
770
+ OperatorServiceClient::new(svc.clone())
771
+ .max_decoding_message_size(get_decode_max_size()),
772
+ );
773
+ let cloud_svc_client = Box::new(
774
+ CloudServiceClient::new(svc.clone()).max_decoding_message_size(get_decode_max_size()),
775
+ );
776
+ let test_svc_client = Box::new(
777
+ TestServiceClient::new(svc.clone()).max_decoding_message_size(get_decode_max_size()),
778
+ );
779
+ let health_svc_client = Box::new(
780
+ HealthClient::new(svc.clone()).max_decoding_message_size(get_decode_max_size()),
781
+ );
782
+
783
+ Self {
784
+ workflow_svc_client,
785
+ operator_svc_client,
786
+ cloud_svc_client,
787
+ test_svc_client,
788
+ health_svc_client,
789
+ }
790
+ }
791
+
792
+ /// Create a service client from implementations of the individual underlying services. Useful
793
+ /// for mocking out service implementations.
794
+ pub fn from_services(
795
+ workflow: Box<dyn WorkflowService>,
796
+ operator: Box<dyn OperatorService>,
797
+ cloud: Box<dyn CloudService>,
798
+ test: Box<dyn TestService>,
799
+ health: Box<dyn HealthService>,
800
+ ) -> Self {
632
801
  Self {
633
- svc,
634
- workflow_svc_client: OnceLock::new(),
635
- operator_svc_client: OnceLock::new(),
636
- cloud_svc_client: OnceLock::new(),
637
- test_svc_client: OnceLock::new(),
638
- health_svc_client: OnceLock::new(),
802
+ workflow_svc_client: workflow,
803
+ operator_svc_client: operator,
804
+ cloud_svc_client: cloud,
805
+ test_svc_client: test,
806
+ health_svc_client: health,
639
807
  }
640
808
  }
809
+
641
810
  /// Get the underlying workflow service client
642
- pub fn workflow_svc(&self) -> &WorkflowServiceClient<T> {
643
- self.workflow_svc_client.get_or_init(|| {
644
- WorkflowServiceClient::new(self.svc.clone())
645
- .max_decoding_message_size(get_decode_max_size())
646
- })
811
+ pub fn workflow_svc(&self) -> Box<dyn WorkflowService> {
812
+ self.workflow_svc_client.clone()
647
813
  }
648
814
  /// Get the underlying operator service client
649
- pub fn operator_svc(&self) -> &OperatorServiceClient<T> {
650
- self.operator_svc_client.get_or_init(|| {
651
- OperatorServiceClient::new(self.svc.clone())
652
- .max_decoding_message_size(get_decode_max_size())
653
- })
815
+ pub fn operator_svc(&self) -> Box<dyn OperatorService> {
816
+ self.operator_svc_client.clone()
654
817
  }
655
818
  /// Get the underlying cloud service client
656
- pub fn cloud_svc(&self) -> &CloudServiceClient<T> {
657
- self.cloud_svc_client.get_or_init(|| {
658
- CloudServiceClient::new(self.svc.clone())
659
- .max_decoding_message_size(get_decode_max_size())
660
- })
819
+ pub fn cloud_svc(&self) -> Box<dyn CloudService> {
820
+ self.cloud_svc_client.clone()
661
821
  }
662
822
  /// Get the underlying test service client
663
- pub fn test_svc(&self) -> &TestServiceClient<T> {
664
- self.test_svc_client.get_or_init(|| {
665
- TestServiceClient::new(self.svc.clone())
666
- .max_decoding_message_size(get_decode_max_size())
667
- })
823
+ pub fn test_svc(&self) -> Box<dyn TestService> {
824
+ self.test_svc_client.clone()
668
825
  }
669
826
  /// Get the underlying health service client
670
- pub fn health_svc(&self) -> &HealthClient<T> {
671
- self.health_svc_client.get_or_init(|| {
672
- HealthClient::new(self.svc.clone()).max_decoding_message_size(get_decode_max_size())
673
- })
674
- }
675
- /// Get the underlying workflow service client mutably
676
- pub fn workflow_svc_mut(&mut self) -> &mut WorkflowServiceClient<T> {
677
- let _ = self.workflow_svc();
678
- self.workflow_svc_client.get_mut().unwrap()
679
- }
680
- /// Get the underlying operator service client mutably
681
- pub fn operator_svc_mut(&mut self) -> &mut OperatorServiceClient<T> {
682
- let _ = self.operator_svc();
683
- self.operator_svc_client.get_mut().unwrap()
684
- }
685
- /// Get the underlying cloud service client mutably
686
- pub fn cloud_svc_mut(&mut self) -> &mut CloudServiceClient<T> {
687
- let _ = self.cloud_svc();
688
- self.cloud_svc_client.get_mut().unwrap()
689
- }
690
- /// Get the underlying test service client mutably
691
- pub fn test_svc_mut(&mut self) -> &mut TestServiceClient<T> {
692
- let _ = self.test_svc();
693
- self.test_svc_client.get_mut().unwrap()
694
- }
695
- /// Get the underlying health service client mutably
696
- pub fn health_svc_mut(&mut self) -> &mut HealthClient<T> {
697
- let _ = self.health_svc();
698
- self.health_svc_client.get_mut().unwrap()
827
+ pub fn health_svc(&self) -> Box<dyn HealthService> {
828
+ self.health_svc_client.clone()
699
829
  }
700
830
  }
701
831
 
702
- /// A [WorkflowServiceClient] with the default interceptors attached.
703
- pub type WorkflowServiceClientWithMetrics = WorkflowServiceClient<InterceptedMetricsSvc>;
704
- /// An [OperatorServiceClient] with the default interceptors attached.
705
- pub type OperatorServiceClientWithMetrics = OperatorServiceClient<InterceptedMetricsSvc>;
706
- /// An [TestServiceClient] with the default interceptors attached.
707
- pub type TestServiceClientWithMetrics = TestServiceClient<InterceptedMetricsSvc>;
708
- /// A [TemporalServiceClient] with the default interceptors attached.
709
- pub type TemporalServiceClientWithMetrics = TemporalServiceClient<InterceptedMetricsSvc>;
710
- type InterceptedMetricsSvc = InterceptedService<GrpcMetricSvc, ServiceCallInterceptor>;
711
-
712
832
  /// Contains an instance of a namespace-bound client for interacting with the Temporal server
713
- #[derive(Debug, Clone)]
833
+ #[derive(Clone)]
714
834
  pub struct Client {
715
835
  /// Client for interacting with workflow service
716
- inner: ConfiguredClient<TemporalServiceClientWithMetrics>,
836
+ inner: ConfiguredClient<TemporalServiceClient>,
717
837
  /// The namespace this client interacts with
718
838
  namespace: String,
719
839
  }
720
840
 
721
841
  impl Client {
722
842
  /// Create a new client from an existing configured lower level client and a namespace
723
- pub fn new(
724
- client: ConfiguredClient<TemporalServiceClientWithMetrics>,
725
- namespace: String,
726
- ) -> Self {
843
+ pub fn new(client: ConfiguredClient<TemporalServiceClient>, namespace: String) -> Self {
727
844
  Client {
728
845
  inner: client,
729
846
  namespace,
730
847
  }
731
848
  }
732
849
 
733
- /// Return an auto-retrying version of the underling grpc client (instrumented with metrics
734
- /// collection, if enabled).
735
- ///
736
- /// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
737
- /// clones will keep re-using the same channel.
738
- pub fn raw_retry_client(&self) -> RetryClient<WorkflowServiceClientWithMetrics> {
739
- RetryClient::new(
740
- self.raw_client().clone(),
741
- self.inner.options.retry_config.clone(),
742
- )
743
- }
744
-
745
- /// Access the underling grpc client. This raw client is not bound to a specific namespace.
746
- ///
747
- /// Note that it is reasonably cheap to clone the returned type if you need to own it. Such
748
- /// clones will keep re-using the same channel.
749
- pub fn raw_client(&self) -> &WorkflowServiceClientWithMetrics {
750
- self.inner.workflow_svc()
751
- }
752
-
753
850
  /// Return the options this client was initialized with
754
851
  pub fn options(&self) -> &ClientOptions {
755
852
  &self.inner.options
@@ -761,23 +858,23 @@ impl Client {
761
858
  }
762
859
 
763
860
  /// Returns a reference to the underlying client
764
- pub fn inner(&self) -> &ConfiguredClient<TemporalServiceClientWithMetrics> {
861
+ pub fn inner(&self) -> &ConfiguredClient<TemporalServiceClient> {
765
862
  &self.inner
766
863
  }
767
864
 
768
865
  /// Consumes self and returns the underlying client
769
- pub fn into_inner(self) -> ConfiguredClient<TemporalServiceClientWithMetrics> {
866
+ pub fn into_inner(self) -> ConfiguredClient<TemporalServiceClient> {
770
867
  self.inner
771
868
  }
772
869
  }
773
870
 
774
871
  impl NamespacedClient for Client {
775
- fn namespace(&self) -> &str {
776
- &self.namespace
872
+ fn namespace(&self) -> String {
873
+ self.namespace.clone()
777
874
  }
778
875
 
779
- fn get_identity(&self) -> &str {
780
- &self.inner.options.identity
876
+ fn identity(&self) -> String {
877
+ self.inner.options.identity.clone()
781
878
  }
782
879
  }
783
880
 
@@ -1100,9 +1197,9 @@ pub trait WorkflowClientTrait: NamespacedClient {
1100
1197
  /// A client that is bound to a namespace
1101
1198
  pub trait NamespacedClient {
1102
1199
  /// Returns the namespace this client is bound to
1103
- fn namespace(&self) -> &str;
1200
+ fn namespace(&self) -> String;
1104
1201
  /// Returns the client identity
1105
- fn get_identity(&self) -> &str;
1202
+ fn identity(&self) -> String;
1106
1203
  }
1107
1204
 
1108
1205
  /// Optional fields supplied at the start of workflow execution
@@ -1242,15 +1339,7 @@ impl From<common::v1::Priority> for Priority {
1242
1339
  #[async_trait::async_trait]
1243
1340
  impl<T> WorkflowClientTrait for T
1244
1341
  where
1245
- T: RawClientLike + NamespacedClient + Clone + Send + Sync + 'static,
1246
- <Self as RawClientLike>::SvcType: GrpcService<Body> + Send + Clone + 'static,
1247
- <<Self as RawClientLike>::SvcType as GrpcService<Body>>::ResponseBody:
1248
- tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
1249
- <<Self as RawClientLike>::SvcType as GrpcService<Body>>::Error:
1250
- Into<tonic::codegen::StdError>,
1251
- <<Self as RawClientLike>::SvcType as GrpcService<Body>>::Future: Send,
1252
- <<<Self as RawClientLike>::SvcType as GrpcService<Body>>::ResponseBody
1253
- as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
1342
+ T: WorkflowService + NamespacedClient + Clone + Send + Sync + 'static,
1254
1343
  {
1255
1344
  async fn start_workflow(
1256
1345
  &self,
@@ -1263,35 +1352,38 @@ where
1263
1352
  ) -> Result<StartWorkflowExecutionResponse> {
1264
1353
  Ok(self
1265
1354
  .clone()
1266
- .start_workflow_execution(StartWorkflowExecutionRequest {
1267
- namespace: self.namespace().to_owned(),
1268
- input: input.into_payloads(),
1269
- workflow_id,
1270
- workflow_type: Some(WorkflowType {
1271
- name: workflow_type,
1272
- }),
1273
- task_queue: Some(TaskQueue {
1274
- name: task_queue,
1275
- kind: TaskQueueKind::Unspecified as i32,
1276
- normal_name: "".to_string(),
1277
- }),
1278
- request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1279
- workflow_id_reuse_policy: options.id_reuse_policy as i32,
1280
- workflow_id_conflict_policy: options.id_conflict_policy as i32,
1281
- workflow_execution_timeout: options
1282
- .execution_timeout
1283
- .and_then(|d| d.try_into().ok()),
1284
- workflow_run_timeout: options.run_timeout.and_then(|d| d.try_into().ok()),
1285
- workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
1286
- search_attributes: options.search_attributes.map(|d| d.into()),
1287
- cron_schedule: options.cron_schedule.unwrap_or_default(),
1288
- request_eager_execution: options.enable_eager_workflow_start,
1289
- retry_policy: options.retry_policy,
1290
- links: options.links,
1291
- completion_callbacks: options.completion_callbacks,
1292
- priority: options.priority.map(Into::into),
1293
- ..Default::default()
1294
- })
1355
+ .start_workflow_execution(
1356
+ StartWorkflowExecutionRequest {
1357
+ namespace: self.namespace(),
1358
+ input: input.into_payloads(),
1359
+ workflow_id,
1360
+ workflow_type: Some(WorkflowType {
1361
+ name: workflow_type,
1362
+ }),
1363
+ task_queue: Some(TaskQueue {
1364
+ name: task_queue,
1365
+ kind: TaskQueueKind::Unspecified as i32,
1366
+ normal_name: "".to_string(),
1367
+ }),
1368
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1369
+ workflow_id_reuse_policy: options.id_reuse_policy as i32,
1370
+ workflow_id_conflict_policy: options.id_conflict_policy as i32,
1371
+ workflow_execution_timeout: options
1372
+ .execution_timeout
1373
+ .and_then(|d| d.try_into().ok()),
1374
+ workflow_run_timeout: options.run_timeout.and_then(|d| d.try_into().ok()),
1375
+ workflow_task_timeout: options.task_timeout.and_then(|d| d.try_into().ok()),
1376
+ search_attributes: options.search_attributes.map(|d| d.into()),
1377
+ cron_schedule: options.cron_schedule.unwrap_or_default(),
1378
+ request_eager_execution: options.enable_eager_workflow_start,
1379
+ retry_policy: options.retry_policy,
1380
+ links: options.links,
1381
+ completion_callbacks: options.completion_callbacks,
1382
+ priority: options.priority.map(Into::into),
1383
+ ..Default::default()
1384
+ }
1385
+ .into_request(),
1386
+ )
1295
1387
  .await?
1296
1388
  .into_inner())
1297
1389
  }
@@ -1302,14 +1394,14 @@ where
1302
1394
  run_id: String,
1303
1395
  ) -> Result<ResetStickyTaskQueueResponse> {
1304
1396
  let request = ResetStickyTaskQueueRequest {
1305
- namespace: self.namespace().to_owned(),
1397
+ namespace: self.namespace(),
1306
1398
  execution: Some(WorkflowExecution {
1307
1399
  workflow_id,
1308
1400
  run_id,
1309
1401
  }),
1310
1402
  };
1311
1403
  Ok(
1312
- WorkflowService::reset_sticky_task_queue(&mut self.clone(), request)
1404
+ WorkflowService::reset_sticky_task_queue(&mut self.clone(), request.into_request())
1313
1405
  .await?
1314
1406
  .into_inner(),
1315
1407
  )
@@ -1320,17 +1412,20 @@ where
1320
1412
  task_token: TaskToken,
1321
1413
  result: Option<Payloads>,
1322
1414
  ) -> Result<RespondActivityTaskCompletedResponse> {
1323
- Ok(self.clone().respond_activity_task_completed(
1324
- RespondActivityTaskCompletedRequest {
1325
- task_token: task_token.0,
1326
- result,
1327
- identity: self.get_identity().to_owned(),
1328
- namespace: self.namespace().to_owned(),
1329
- ..Default::default()
1330
- },
1331
- )
1332
- .await?
1333
- .into_inner())
1415
+ Ok(self
1416
+ .clone()
1417
+ .respond_activity_task_completed(
1418
+ RespondActivityTaskCompletedRequest {
1419
+ task_token: task_token.0,
1420
+ result,
1421
+ identity: self.identity(),
1422
+ namespace: self.namespace(),
1423
+ ..Default::default()
1424
+ }
1425
+ .into_request(),
1426
+ )
1427
+ .await?
1428
+ .into_inner())
1334
1429
  }
1335
1430
 
1336
1431
  async fn record_activity_heartbeat(
@@ -1338,16 +1433,19 @@ where
1338
1433
  task_token: TaskToken,
1339
1434
  details: Option<Payloads>,
1340
1435
  ) -> Result<RecordActivityTaskHeartbeatResponse> {
1341
- Ok(self.clone().record_activity_task_heartbeat(
1342
- RecordActivityTaskHeartbeatRequest {
1343
- task_token: task_token.0,
1344
- details,
1345
- identity: self.get_identity().to_owned(),
1346
- namespace: self.namespace().to_owned(),
1347
- },
1348
- )
1349
- .await?
1350
- .into_inner())
1436
+ Ok(self
1437
+ .clone()
1438
+ .record_activity_task_heartbeat(
1439
+ RecordActivityTaskHeartbeatRequest {
1440
+ task_token: task_token.0,
1441
+ details,
1442
+ identity: self.identity(),
1443
+ namespace: self.namespace(),
1444
+ }
1445
+ .into_request(),
1446
+ )
1447
+ .await?
1448
+ .into_inner())
1351
1449
  }
1352
1450
 
1353
1451
  async fn cancel_activity_task(
@@ -1355,17 +1453,20 @@ where
1355
1453
  task_token: TaskToken,
1356
1454
  details: Option<Payloads>,
1357
1455
  ) -> Result<RespondActivityTaskCanceledResponse> {
1358
- Ok(self.clone().respond_activity_task_canceled(
1359
- RespondActivityTaskCanceledRequest {
1360
- task_token: task_token.0,
1361
- details,
1362
- identity: self.get_identity().to_owned(),
1363
- namespace: self.namespace().to_owned(),
1364
- ..Default::default()
1365
- },
1366
- )
1367
- .await?
1368
- .into_inner())
1456
+ Ok(self
1457
+ .clone()
1458
+ .respond_activity_task_canceled(
1459
+ RespondActivityTaskCanceledRequest {
1460
+ task_token: task_token.0,
1461
+ details,
1462
+ identity: self.identity(),
1463
+ namespace: self.namespace(),
1464
+ ..Default::default()
1465
+ }
1466
+ .into_request(),
1467
+ )
1468
+ .await?
1469
+ .into_inner())
1369
1470
  }
1370
1471
 
1371
1472
  async fn signal_workflow_execution(
@@ -1376,19 +1477,21 @@ where
1376
1477
  payloads: Option<Payloads>,
1377
1478
  request_id: Option<String>,
1378
1479
  ) -> Result<SignalWorkflowExecutionResponse> {
1379
- Ok(WorkflowService::signal_workflow_execution(&mut self.clone(),
1480
+ Ok(WorkflowService::signal_workflow_execution(
1481
+ &mut self.clone(),
1380
1482
  SignalWorkflowExecutionRequest {
1381
- namespace: self.namespace().to_owned(),
1483
+ namespace: self.namespace(),
1382
1484
  workflow_execution: Some(WorkflowExecution {
1383
1485
  workflow_id,
1384
1486
  run_id,
1385
1487
  }),
1386
1488
  signal_name,
1387
1489
  input: payloads,
1388
- identity: self.get_identity().to_owned(),
1490
+ identity: self.identity(),
1389
1491
  request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1390
1492
  ..Default::default()
1391
- },
1493
+ }
1494
+ .into_request(),
1392
1495
  )
1393
1496
  .await?
1394
1497
  .into_inner())
@@ -1399,9 +1502,10 @@ where
1399
1502
  options: SignalWithStartOptions,
1400
1503
  workflow_options: WorkflowOptions,
1401
1504
  ) -> Result<SignalWithStartWorkflowExecutionResponse> {
1402
- Ok(WorkflowService::signal_with_start_workflow_execution(&mut self.clone(),
1505
+ Ok(WorkflowService::signal_with_start_workflow_execution(
1506
+ &mut self.clone(),
1403
1507
  SignalWithStartWorkflowExecutionRequest {
1404
- namespace: self.namespace().to_owned(),
1508
+ namespace: self.namespace(),
1405
1509
  workflow_id: options.workflow_id,
1406
1510
  workflow_type: Some(WorkflowType {
1407
1511
  name: options.workflow_type,
@@ -1414,7 +1518,7 @@ where
1414
1518
  input: options.input,
1415
1519
  signal_name: options.signal_name,
1416
1520
  signal_input: options.signal_input,
1417
- identity: self.get_identity().to_owned(),
1521
+ identity: self.identity(),
1418
1522
  request_id: options
1419
1523
  .request_id
1420
1524
  .unwrap_or_else(|| Uuid::new_v4().to_string()),
@@ -1431,7 +1535,8 @@ where
1431
1535
  cron_schedule: workflow_options.cron_schedule.unwrap_or_default(),
1432
1536
  header: options.signal_header,
1433
1537
  ..Default::default()
1434
- },
1538
+ }
1539
+ .into_request(),
1435
1540
  )
1436
1541
  .await?
1437
1542
  .into_inner())
@@ -1443,19 +1548,22 @@ where
1443
1548
  run_id: String,
1444
1549
  query: WorkflowQuery,
1445
1550
  ) -> Result<QueryWorkflowResponse> {
1446
- Ok(self.clone().query_workflow(
1447
- QueryWorkflowRequest {
1448
- namespace: self.namespace().to_owned(),
1449
- execution: Some(WorkflowExecution {
1450
- workflow_id,
1451
- run_id,
1452
- }),
1453
- query: Some(query),
1454
- query_reject_condition: 1,
1455
- },
1456
- )
1457
- .await?
1458
- .into_inner())
1551
+ Ok(self
1552
+ .clone()
1553
+ .query_workflow(
1554
+ QueryWorkflowRequest {
1555
+ namespace: self.namespace(),
1556
+ execution: Some(WorkflowExecution {
1557
+ workflow_id,
1558
+ run_id,
1559
+ }),
1560
+ query: Some(query),
1561
+ query_reject_condition: 1,
1562
+ }
1563
+ .into_request(),
1564
+ )
1565
+ .await?
1566
+ .into_inner())
1459
1567
  }
1460
1568
 
1461
1569
  async fn describe_workflow_execution(
@@ -1463,14 +1571,16 @@ where
1463
1571
  workflow_id: String,
1464
1572
  run_id: Option<String>,
1465
1573
  ) -> Result<DescribeWorkflowExecutionResponse> {
1466
- Ok(WorkflowService::describe_workflow_execution(&mut self.clone(),
1574
+ Ok(WorkflowService::describe_workflow_execution(
1575
+ &mut self.clone(),
1467
1576
  DescribeWorkflowExecutionRequest {
1468
- namespace: self.namespace().to_owned(),
1577
+ namespace: self.namespace(),
1469
1578
  execution: Some(WorkflowExecution {
1470
1579
  workflow_id,
1471
1580
  run_id: run_id.unwrap_or_default(),
1472
1581
  }),
1473
- },
1582
+ }
1583
+ .into_request(),
1474
1584
  )
1475
1585
  .await?
1476
1586
  .into_inner())
@@ -1482,16 +1592,18 @@ where
1482
1592
  run_id: Option<String>,
1483
1593
  page_token: Vec<u8>,
1484
1594
  ) -> Result<GetWorkflowExecutionHistoryResponse> {
1485
- Ok(WorkflowService::get_workflow_execution_history(&mut self.clone(),
1595
+ Ok(WorkflowService::get_workflow_execution_history(
1596
+ &mut self.clone(),
1486
1597
  GetWorkflowExecutionHistoryRequest {
1487
- namespace: self.namespace().to_owned(),
1598
+ namespace: self.namespace(),
1488
1599
  execution: Some(WorkflowExecution {
1489
1600
  workflow_id,
1490
1601
  run_id: run_id.unwrap_or_default(),
1491
1602
  }),
1492
1603
  next_page_token: page_token,
1493
1604
  ..Default::default()
1494
- },
1605
+ }
1606
+ .into_request(),
1495
1607
  )
1496
1608
  .await?
1497
1609
  .into_inner())
@@ -1504,22 +1616,25 @@ where
1504
1616
  reason: String,
1505
1617
  request_id: Option<String>,
1506
1618
  ) -> Result<RequestCancelWorkflowExecutionResponse> {
1507
- Ok(self.clone().request_cancel_workflow_execution(
1508
- RequestCancelWorkflowExecutionRequest {
1509
- namespace: self.namespace().to_owned(),
1510
- workflow_execution: Some(WorkflowExecution {
1511
- workflow_id,
1512
- run_id: run_id.unwrap_or_default(),
1513
- }),
1514
- identity: self.get_identity().to_owned(),
1515
- request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1516
- first_execution_run_id: "".to_string(),
1517
- reason,
1518
- links: vec![],
1519
- },
1520
- )
1521
- .await?
1522
- .into_inner())
1619
+ Ok(self
1620
+ .clone()
1621
+ .request_cancel_workflow_execution(
1622
+ RequestCancelWorkflowExecutionRequest {
1623
+ namespace: self.namespace(),
1624
+ workflow_execution: Some(WorkflowExecution {
1625
+ workflow_id,
1626
+ run_id: run_id.unwrap_or_default(),
1627
+ }),
1628
+ identity: self.identity(),
1629
+ request_id: request_id.unwrap_or_else(|| Uuid::new_v4().to_string()),
1630
+ first_execution_run_id: "".to_string(),
1631
+ reason,
1632
+ links: vec![],
1633
+ }
1634
+ .into_request(),
1635
+ )
1636
+ .await?
1637
+ .into_inner())
1523
1638
  }
1524
1639
 
1525
1640
  async fn terminate_workflow_execution(
@@ -1527,19 +1642,21 @@ where
1527
1642
  workflow_id: String,
1528
1643
  run_id: Option<String>,
1529
1644
  ) -> Result<TerminateWorkflowExecutionResponse> {
1530
- Ok(WorkflowService::terminate_workflow_execution(&mut self.clone(),
1645
+ Ok(WorkflowService::terminate_workflow_execution(
1646
+ &mut self.clone(),
1531
1647
  TerminateWorkflowExecutionRequest {
1532
- namespace: self.namespace().to_owned(),
1648
+ namespace: self.namespace(),
1533
1649
  workflow_execution: Some(WorkflowExecution {
1534
1650
  workflow_id,
1535
1651
  run_id: run_id.unwrap_or_default(),
1536
1652
  }),
1537
1653
  reason: "".to_string(),
1538
1654
  details: None,
1539
- identity: self.get_identity().to_owned(),
1655
+ identity: self.identity(),
1540
1656
  first_execution_run_id: "".to_string(),
1541
1657
  links: vec![],
1542
- },
1658
+ }
1659
+ .into_request(),
1543
1660
  )
1544
1661
  .await?
1545
1662
  .into_inner())
@@ -1551,23 +1668,25 @@ where
1551
1668
  ) -> Result<RegisterNamespaceResponse> {
1552
1669
  let req = Into::<RegisterNamespaceRequest>::into(options);
1553
1670
  Ok(
1554
- WorkflowService::register_namespace(&mut self.clone(),req)
1671
+ WorkflowService::register_namespace(&mut self.clone(), req.into_request())
1555
1672
  .await?
1556
1673
  .into_inner(),
1557
1674
  )
1558
1675
  }
1559
1676
 
1560
1677
  async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
1561
- Ok(WorkflowService::list_namespaces(&mut self.clone(),
1562
- ListNamespacesRequest::default(),
1678
+ Ok(WorkflowService::list_namespaces(
1679
+ &mut self.clone(),
1680
+ ListNamespacesRequest::default().into_request(),
1563
1681
  )
1564
1682
  .await?
1565
1683
  .into_inner())
1566
1684
  }
1567
1685
 
1568
1686
  async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
1569
- Ok(WorkflowService::describe_namespace(&mut self.clone(),
1570
- namespace.into_describe_namespace_request(),
1687
+ Ok(WorkflowService::describe_namespace(
1688
+ &mut self.clone(),
1689
+ namespace.into_describe_namespace_request().into_request(),
1571
1690
  )
1572
1691
  .await?
1573
1692
  .into_inner())
@@ -1580,14 +1699,16 @@ where
1580
1699
  start_time_filter: Option<StartTimeFilter>,
1581
1700
  filters: Option<ListOpenFilters>,
1582
1701
  ) -> Result<ListOpenWorkflowExecutionsResponse> {
1583
- Ok(WorkflowService::list_open_workflow_executions(&mut self.clone(),
1702
+ Ok(WorkflowService::list_open_workflow_executions(
1703
+ &mut self.clone(),
1584
1704
  ListOpenWorkflowExecutionsRequest {
1585
- namespace: self.namespace().to_owned(),
1705
+ namespace: self.namespace(),
1586
1706
  maximum_page_size,
1587
1707
  next_page_token,
1588
1708
  start_time_filter,
1589
1709
  filters,
1590
- },
1710
+ }
1711
+ .into_request(),
1591
1712
  )
1592
1713
  .await?
1593
1714
  .into_inner())
@@ -1600,14 +1721,16 @@ where
1600
1721
  start_time_filter: Option<StartTimeFilter>,
1601
1722
  filters: Option<ListClosedFilters>,
1602
1723
  ) -> Result<ListClosedWorkflowExecutionsResponse> {
1603
- Ok(WorkflowService::list_closed_workflow_executions(&mut self.clone(),
1724
+ Ok(WorkflowService::list_closed_workflow_executions(
1725
+ &mut self.clone(),
1604
1726
  ListClosedWorkflowExecutionsRequest {
1605
- namespace: self.namespace().to_owned(),
1727
+ namespace: self.namespace(),
1606
1728
  maximum_page_size,
1607
1729
  next_page_token,
1608
1730
  start_time_filter,
1609
1731
  filters,
1610
- },
1732
+ }
1733
+ .into_request(),
1611
1734
  )
1612
1735
  .await?
1613
1736
  .into_inner())
@@ -1619,13 +1742,15 @@ where
1619
1742
  next_page_token: Vec<u8>,
1620
1743
  query: String,
1621
1744
  ) -> Result<ListWorkflowExecutionsResponse> {
1622
- Ok(WorkflowService::list_workflow_executions(&mut self.clone(),
1745
+ Ok(WorkflowService::list_workflow_executions(
1746
+ &mut self.clone(),
1623
1747
  ListWorkflowExecutionsRequest {
1624
- namespace: self.namespace().to_owned(),
1748
+ namespace: self.namespace(),
1625
1749
  page_size,
1626
1750
  next_page_token,
1627
1751
  query,
1628
- },
1752
+ }
1753
+ .into_request(),
1629
1754
  )
1630
1755
  .await?
1631
1756
  .into_inner())
@@ -1637,21 +1762,24 @@ where
1637
1762
  next_page_token: Vec<u8>,
1638
1763
  query: String,
1639
1764
  ) -> Result<ListArchivedWorkflowExecutionsResponse> {
1640
- Ok(WorkflowService::list_archived_workflow_executions(&mut self.clone(),
1765
+ Ok(WorkflowService::list_archived_workflow_executions(
1766
+ &mut self.clone(),
1641
1767
  ListArchivedWorkflowExecutionsRequest {
1642
- namespace: self.namespace().to_owned(),
1768
+ namespace: self.namespace(),
1643
1769
  page_size,
1644
1770
  next_page_token,
1645
1771
  query,
1646
- },
1772
+ }
1773
+ .into_request(),
1647
1774
  )
1648
1775
  .await?
1649
1776
  .into_inner())
1650
1777
  }
1651
1778
 
1652
1779
  async fn get_search_attributes(&self) -> Result<GetSearchAttributesResponse> {
1653
- Ok(WorkflowService::get_search_attributes(&mut self.clone(),
1654
- GetSearchAttributesRequest {},
1780
+ Ok(WorkflowService::get_search_attributes(
1781
+ &mut self.clone(),
1782
+ GetSearchAttributesRequest {}.into_request(),
1655
1783
  )
1656
1784
  .await?
1657
1785
  .into_inner())
@@ -1665,9 +1793,10 @@ where
1665
1793
  wait_policy: update::v1::WaitPolicy,
1666
1794
  args: Option<Payloads>,
1667
1795
  ) -> Result<UpdateWorkflowExecutionResponse> {
1668
- Ok(WorkflowService::update_workflow_execution(&mut self.clone(),
1796
+ Ok(WorkflowService::update_workflow_execution(
1797
+ &mut self.clone(),
1669
1798
  UpdateWorkflowExecutionRequest {
1670
- namespace: self.namespace().to_owned(),
1799
+ namespace: self.namespace(),
1671
1800
  workflow_execution: Some(WorkflowExecution {
1672
1801
  workflow_id,
1673
1802
  run_id,
@@ -1676,7 +1805,7 @@ where
1676
1805
  request: Some(update::v1::Request {
1677
1806
  meta: Some(update::v1::Meta {
1678
1807
  update_id: "".into(),
1679
- identity: self.get_identity().to_owned(),
1808
+ identity: self.identity(),
1680
1809
  }),
1681
1810
  input: Some(update::v1::Input {
1682
1811
  header: None,
@@ -1685,7 +1814,8 @@ where
1685
1814
  }),
1686
1815
  }),
1687
1816
  ..Default::default()
1688
- },
1817
+ }
1818
+ .into_request(),
1689
1819
  )
1690
1820
  .await?
1691
1821
  .into_inner())
@@ -1693,17 +1823,9 @@ where
1693
1823
  }
1694
1824
 
1695
1825
  mod sealed {
1696
- use crate::{InterceptedMetricsSvc, RawClientLike, WorkflowClientTrait};
1697
-
1698
- pub trait WfHandleClient:
1699
- WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
1700
- {
1701
- }
1702
-
1703
- impl<T> WfHandleClient for T where
1704
- T: WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
1705
- {
1706
- }
1826
+ use crate::{WorkflowClientTrait, WorkflowService};
1827
+ pub trait WfHandleClient: WorkflowClientTrait + WorkflowService {}
1828
+ impl<T> WfHandleClient for T where T: WorkflowClientTrait + WorkflowService {}
1707
1829
  }
1708
1830
 
1709
1831
  /// Additional methods for workflow clients
@@ -1719,7 +1841,7 @@ pub trait WfClientExt: WfHandleClient + Sized + Clone {
1719
1841
  UntypedWorkflowHandle::new(
1720
1842
  self.clone(),
1721
1843
  WorkflowExecutionInfo {
1722
- namespace: self.namespace().to_string(),
1844
+ namespace: self.namespace(),
1723
1845
  workflow_id: workflow_id.into(),
1724
1846
  run_id: if rid.is_empty() { None } else { Some(rid) },
1725
1847
  },
@@ -1768,13 +1890,17 @@ mod tests {
1768
1890
  // Initial header set
1769
1891
  let headers = Arc::new(RwLock::new(ClientHeaders {
1770
1892
  user_headers: HashMap::new(),
1893
+ user_binary_headers: HashMap::new(),
1771
1894
  api_key: Some("my-api-key".to_owned()),
1772
1895
  }));
1773
- headers
1774
- .clone()
1775
- .write()
1776
- .user_headers
1777
- .insert("my-meta-key".to_owned(), "my-meta-val".to_owned());
1896
+ headers.clone().write().user_headers.insert(
1897
+ "my-meta-key".parse().unwrap(),
1898
+ "my-meta-val".parse().unwrap(),
1899
+ );
1900
+ headers.clone().write().user_binary_headers.insert(
1901
+ "my-bin-meta-key-bin".parse().unwrap(),
1902
+ vec![1, 2, 3].try_into().unwrap(),
1903
+ );
1778
1904
  let mut interceptor = ServiceCallInterceptor {
1779
1905
  opts,
1780
1906
  headers: headers.clone(),
@@ -1787,6 +1913,10 @@ mod tests {
1787
1913
  req.metadata().get("authorization").unwrap(),
1788
1914
  "Bearer my-api-key"
1789
1915
  );
1916
+ assert_eq!(
1917
+ req.metadata().get_bin("my-bin-meta-key-bin").unwrap(),
1918
+ vec![1, 2, 3].as_slice()
1919
+ );
1790
1920
 
1791
1921
  // Overwrite at request time
1792
1922
  let mut req = tonic::Request::new(());
@@ -1794,26 +1924,33 @@ mod tests {
1794
1924
  .insert("my-meta-key", "my-meta-val2".parse().unwrap());
1795
1925
  req.metadata_mut()
1796
1926
  .insert("authorization", "my-api-key2".parse().unwrap());
1927
+ req.metadata_mut()
1928
+ .insert_bin("my-bin-meta-key-bin", vec![4, 5, 6].try_into().unwrap());
1797
1929
  let req = interceptor.call(req).unwrap();
1798
1930
  assert_eq!(req.metadata().get("my-meta-key").unwrap(), "my-meta-val2");
1799
1931
  assert_eq!(req.metadata().get("authorization").unwrap(), "my-api-key2");
1932
+ assert_eq!(
1933
+ req.metadata().get_bin("my-bin-meta-key-bin").unwrap(),
1934
+ vec![4, 5, 6].as_slice()
1935
+ );
1800
1936
 
1801
1937
  // Overwrite auth on header
1802
- headers
1803
- .clone()
1804
- .write()
1805
- .user_headers
1806
- .insert("authorization".to_owned(), "my-api-key3".to_owned());
1938
+ headers.clone().write().user_headers.insert(
1939
+ "authorization".parse().unwrap(),
1940
+ "my-api-key3".parse().unwrap(),
1941
+ );
1807
1942
  let req = interceptor.call(tonic::Request::new(())).unwrap();
1808
1943
  assert_eq!(req.metadata().get("my-meta-key").unwrap(), "my-meta-val");
1809
1944
  assert_eq!(req.metadata().get("authorization").unwrap(), "my-api-key3");
1810
1945
 
1811
1946
  // Remove headers and auth and confirm gone
1812
1947
  headers.clone().write().user_headers.clear();
1948
+ headers.clone().write().user_binary_headers.clear();
1813
1949
  headers.clone().write().api_key.take();
1814
1950
  let req = interceptor.call(tonic::Request::new(())).unwrap();
1815
1951
  assert!(!req.metadata().contains_key("my-meta-key"));
1816
1952
  assert!(!req.metadata().contains_key("authorization"));
1953
+ assert!(!req.metadata().contains_key("my-bin-meta-key-bin"));
1817
1954
 
1818
1955
  // Timeout header not overriden
1819
1956
  let mut req = tonic::Request::new(());
@@ -1826,6 +1963,55 @@ mod tests {
1826
1963
  );
1827
1964
  }
1828
1965
 
1966
+ #[test]
1967
+ fn invalid_ascii_header_key() {
1968
+ let invalid_headers = {
1969
+ let mut h = HashMap::new();
1970
+ h.insert("x-binary-key-bin".to_owned(), "value".to_owned());
1971
+ h
1972
+ };
1973
+
1974
+ let result = parse_ascii_headers(invalid_headers);
1975
+ assert!(result.is_err());
1976
+ assert_eq!(
1977
+ result.err().unwrap().to_string(),
1978
+ "Invalid ASCII header key 'x-binary-key-bin': invalid gRPC metadata key name"
1979
+ );
1980
+ }
1981
+
1982
+ #[test]
1983
+ fn invalid_ascii_header_value() {
1984
+ let invalid_headers = {
1985
+ let mut h = HashMap::new();
1986
+ // Nul bytes are valid UTF-8, but not valid ascii gRPC headers:
1987
+ h.insert("x-ascii-key".to_owned(), "\x00value".to_owned());
1988
+ h
1989
+ };
1990
+
1991
+ let result = parse_ascii_headers(invalid_headers);
1992
+ assert!(result.is_err());
1993
+ assert_eq!(
1994
+ result.err().unwrap().to_string(),
1995
+ "Invalid ASCII header value for key 'x-ascii-key': failed to parse metadata value"
1996
+ );
1997
+ }
1998
+
1999
+ #[test]
2000
+ fn invalid_binary_header_key() {
2001
+ let invalid_headers = {
2002
+ let mut h = HashMap::new();
2003
+ h.insert("x-ascii-key".to_owned(), vec![1, 2, 3]);
2004
+ h
2005
+ };
2006
+
2007
+ let result = parse_binary_headers(invalid_headers);
2008
+ assert!(result.is_err());
2009
+ assert_eq!(
2010
+ result.err().unwrap().to_string(),
2011
+ "Invalid binary header key 'x-ascii-key': invalid gRPC metadata key name"
2012
+ );
2013
+ }
2014
+
1829
2015
  #[test]
1830
2016
  fn keep_alive_defaults() {
1831
2017
  let mut builder = ClientOptionsBuilder::default();