temporalio_client/options_structs.rs
1use crate::{
2 ClientInterceptor, HttpConnectProxyOptions, RetryOptions, RpcOptions, VERSION, callback_based,
3};
4use http::Uri;
5use std::{collections::HashMap, sync::Arc, time::Duration};
6use temporalio_common::{
7 RetryPolicy,
8 data_converters::DataConverter,
9 protos::temporal::api::{
10 common::{
11 self,
12 v1::{Header, Payloads},
13 },
14 enums::v1::{
15 ArchivalState, HistoryEventFilterType, QueryRejectCondition, WorkflowIdConflictPolicy,
16 WorkflowIdReusePolicy,
17 },
18 replication::v1::ClusterReplicationConfig,
19 workflowservice::v1::RegisterNamespaceRequest,
20 },
21 search_attributes::SearchAttributes,
22 telemetry::metrics::TemporalMeter,
23};
24use tokio_rustls::rustls::client::danger::ServerCertVerifier;
25use url::Url;
26
27/// Options for [crate::Connection::connect].
28#[derive(bon::Builder, Clone, Debug)]
29#[non_exhaustive]
30#[builder(start_fn = new, on(String, into), state_mod(vis = "pub"))]
31pub struct ConnectionOptions {
32 /// The server to connect to.
33 #[builder(start_fn, into)]
34 pub target: Url,
35 /// A human-readable string that can identify this process. Defaults to empty string.
36 #[builder(default)]
37 pub identity: String,
38 /// When set, this client will record metrics using the provided meter. The meter can be
39 /// obtained from [temporalio_common::telemetry::TelemetryInstance::get_temporal_metric_meter].
40 pub metrics_meter: Option<TemporalMeter>,
41 /// If specified, use TLS as configured by the [TlsOptions] struct. If this is set core will
42 /// attempt to use TLS when connecting to the Temporal server. Lang SDK is expected to pass any
43 /// certs or keys as bytes, loading them from disk itself if needed.
44 pub tls_options: Option<TlsOptions>,
45 /// If set, override the origin used when connecting. May be useful in rare situations where tls
46 /// verification needs to use a different name from what should be set as the `:authority`
47 /// header. If [TlsOptions::domain] is set, and this is not, this will be set to
48 /// `https://<domain>`, effectively making the `:authority` header consistent with the domain
49 /// override.
50 pub override_origin: Option<Uri>,
51 /// An API key to use for auth. If set, TLS will be enabled by default, but without any mTLS
52 /// specific settings.
53 pub api_key: Option<String>,
54 /// When set, limits the time allowed to establish the initial TCP/TLS connection to the
55 /// server. If the connection cannot be established within this duration, `connect` will
56 /// return an error. When `None` (the default), no explicit timeout is applied and the
57 /// connection attempt may block indefinitely (subject to OS-level TCP timeouts).
58 pub connect_timeout: Option<Duration>,
59 /// Retry configuration for the server client. Default is [RetryOptions::default]
60 #[builder(default)]
61 pub retry_options: RetryOptions,
62 /// If set, HTTP2 gRPC keep alive will be enabled.
63 /// To enable with default settings, use `.keep_alive(Some(ClientKeepAliveConfig::default()))`.
64 #[builder(required, default = Some(ClientKeepAliveOptions::default()))]
65 pub keep_alive: Option<ClientKeepAliveOptions>,
66 /// HTTP headers to include on every RPC call.
67 ///
68 /// These must be valid gRPC metadata keys, and must not be binary metadata keys (ending in
69 /// `-bin). To set binary headers, use [ConnectionOptions::binary_headers]. Invalid header keys
70 /// or values will cause an error to be returned when connecting.
71 pub headers: Option<HashMap<String, String>>,
72 /// HTTP headers to include on every RPC call as binary gRPC metadata (encoded as base64).
73 ///
74 /// These must be valid binary gRPC metadata keys (and end with a `-bin` suffix). Invalid
75 /// header keys will cause an error to be returned when connecting.
76 pub binary_headers: Option<HashMap<String, Vec<u8>>>,
77 /// HTTP CONNECT proxy to use for this client.
78 pub http_connect_proxy: Option<HttpConnectProxyOptions>,
79 /// If set, DNS-based load balancing is enabled. When the target is a hostname (not an IP
80 /// literal), DNS is resolved to all addresses and requests are distributed across them.
81 /// Incompatible with `service_override` and `http_connect_proxy`. Setting either in addition
82 /// to this field is an error. Set to `None` to disable.
83 #[builder(required, default = Some(DnsLoadBalancingOptions::default()))]
84 pub dns_load_balancing: Option<DnsLoadBalancingOptions>,
85 /// If set true, error code labels will not be included on request failure metrics.
86 #[builder(default)]
87 pub disable_error_code_metric_tags: bool,
88 /// If set, all gRPC calls will be routed through the provided service.
89 pub service_override: Option<callback_based::CallbackBasedGrpcService>,
90 /// Controls transport-level gRPC compression for the client. Defaults to
91 /// [GrpcCompression::Gzip], which compresses outbound request bodies and accepts
92 /// compressed responses. Set to [GrpcCompression::None] to opt out.
93 /// If service_override is specified, is forced to `None`.
94 #[builder(default)]
95 pub grpc_compression: GrpcCompression,
96 /// Payload size limit options for this connection. Defaults to the standard warning thresholds;
97 /// disable an individual warning by setting its threshold to `0`.
98 /// NOTE: Experimental
99 #[builder(default)]
100 pub payload_limits: PayloadLimitsOptions,
101
102 // Internal / Core-based SDK only options below =============================================
103 /// If set true, get_system_info will not be called upon connection.
104 #[builder(default)]
105 #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
106 pub(crate) skip_get_system_info: bool,
107 /// The name of the SDK being implemented on top of core. Is set as `client-name` header in
108 /// all RPC calls
109 #[builder(default = "temporal-rust".to_owned())]
110 #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
111 pub(crate) client_name: String,
112 // TODO [rust-sdk-branch]: SDK should set this to its version. Doing that probably easiest
113 // after adding proper client interceptors.
114 /// The version of the SDK being implemented on top of core. Is set as `client-version` header
115 /// in all RPC calls. The server decides if the client is supported based on this.
116 #[builder(default = VERSION.to_owned())]
117 #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
118 pub(crate) client_version: String,
119}
120
121// Setters/getters for fields that should only be touched by SDK implementers.
122#[cfg(feature = "core-based-sdk")]
123impl ConnectionOptions {
124 /// Set whether or not get_system_info will be called upon connection.
125 pub fn set_skip_get_system_info(&mut self, skip: bool) {
126 self.skip_get_system_info = skip;
127 }
128 /// Get whether or not get_system_info will be called upon connection.
129 pub fn get_skip_get_system_info(&self) -> bool {
130 self.skip_get_system_info
131 }
132 /// Get the name of the SDK being implemented on top of core.
133 pub fn get_client_name(&self) -> &str {
134 &self.client_name
135 }
136 /// Get the version of the SDK being implemented on top of core.
137 pub fn get_client_version(&self) -> &str {
138 &self.client_version
139 }
140}
141
142/// Options for [crate::Client::new].
143#[derive(Clone, derive_more::Debug, bon::Builder)]
144#[non_exhaustive]
145#[builder(start_fn = new, on(String, into), state_mod(vis = "pub"))]
146pub struct ClientOptions {
147 /// The namespace this client will be bound to.
148 #[builder(start_fn)]
149 pub namespace: String,
150 /// The data converter used for serializing/deserializing payloads.
151 #[builder(default)]
152 pub data_converter: DataConverter,
153 /// Interceptors for high-level client operations, ordered outermost to innermost.
154 #[builder(default)]
155 #[debug(skip)]
156 pub client_interceptors: Vec<Arc<dyn ClientInterceptor>>,
157}
158
159/// Selects the transport-level compression used for gRPC calls. See
160/// [ConnectionOptions::grpc_compression].
161#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
162#[non_exhaustive]
163pub enum GrpcCompression {
164 /// Do not compress requests or advertise acceptance of compressed responses.
165 None,
166 /// Gzip-compress outbound requests and accept gzip-compressed responses.
167 #[default]
168 Gzip,
169}
170
171/// Configuration options for TLS
172#[derive(Clone, Default)]
173pub struct TlsOptions {
174 /// Bytes representing the root CA certificate used by the server. If not set, and the server's
175 /// cert is issued by someone the operating system trusts, verification will still work (ex:
176 /// Cloud offering).
177 pub server_root_ca_cert: Option<Vec<u8>>,
178 /// Sets the domain name against which to verify the server's TLS certificate. If not provided,
179 /// the domain name will be extracted from the URL used to connect.
180 pub domain: Option<String>,
181 /// TLS info for the client. If specified, core will attempt to use mTLS.
182 pub client_tls_options: Option<ClientTlsOptions>,
183 /// Optional custom server certificate verifier. When set, this replaces the default
184 /// certificate verification and `server_root_ca_cert` is ignored.
185 ///
186 /// This is useful for:
187 /// - Certificate pinning
188 /// - Custom trust-domain validation (e.g., SAN-URI extraction)
189 /// - Federated root certificate stores
190 ///
191 /// # WARNING
192 /// Implementing a custom `ServerCertVerifier` can lead to severely insecure TLS connections
193 /// (e.g., disabling all validation or allowing man-in-the-middle attacks) if not done carefully.
194 /// Only use this if you know exactly what you are doing.
195 ///
196 /// The verifier must implement [`ServerCertVerifier`] from the `rustls` crate.
197 /// Note that `domain` is still respected for the `:authority` header / origin override
198 /// even when a custom verifier is set.
199 pub server_cert_verifier: Option<Arc<dyn ServerCertVerifier>>,
200}
201
202impl std::fmt::Debug for TlsOptions {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 f.debug_struct("TlsOptions")
205 .field(
206 "server_root_ca_cert",
207 &self
208 .server_root_ca_cert
209 .as_ref()
210 .map(|c| format!("{} bytes", c.len())),
211 )
212 .field("domain", &self.domain)
213 .field("client_tls_options", &self.client_tls_options)
214 .field(
215 "server_cert_verifier",
216 &self.server_cert_verifier.as_ref().map(|_| "<custom>"),
217 )
218 .finish()
219 }
220}
221
222/// If using mTLS, both the client cert and private key must be specified, this contains them.
223#[derive(Clone)]
224pub struct ClientTlsOptions {
225 /// The certificate for this client, encoded as PEM
226 pub client_cert: Vec<u8>,
227 /// The private key for this client, encoded as PEM
228 pub client_private_key: Vec<u8>,
229}
230
231/// Client keep alive configuration.
232#[derive(Clone, Debug)]
233pub struct ClientKeepAliveOptions {
234 /// Interval to send HTTP2 keep alive pings.
235 pub interval: Duration,
236 /// Timeout that the keep alive must be responded to within or the connection will be closed.
237 pub timeout: Duration,
238}
239
240impl Default for ClientKeepAliveOptions {
241 fn default() -> Self {
242 Self {
243 interval: Duration::from_secs(30),
244 timeout: Duration::from_secs(15),
245 }
246 }
247}
248
249/// Options for DNS-based load balancing.
250#[derive(Clone, Debug)]
251#[non_exhaustive]
252pub struct DnsLoadBalancingOptions {
253 /// How often to re-resolve DNS. Defaults to 30 seconds.
254 pub resolution_interval: Duration,
255}
256
257impl Default for DnsLoadBalancingOptions {
258 fn default() -> Self {
259 Self {
260 resolution_interval: Duration::from_secs(30),
261 }
262 }
263}
264
265/// Payload size limit options for a connection.
266/// NOTE: Experimental
267#[derive(Clone, Debug)]
268pub struct PayloadLimitsOptions {
269 /// Warning threshold (bytes) for the size of an outbound payload-bearing field; over-threshold
270 /// fields are logged but still sent to server. Defaults to 512 KiB. Set to `0` to disable.
271 pub payloads_warn_size: u64,
272 /// Warning threshold (bytes) for outbound memo sizes; over-threshold memos are logged but still
273 /// sent to server. Defaults to 2 KiB. Set to `0` to disable.
274 pub memo_warn_size: u64,
275}
276
277impl Default for PayloadLimitsOptions {
278 fn default() -> Self {
279 Self {
280 payloads_warn_size: 512 * 1024,
281 memo_warn_size: 2 * 1024,
282 }
283 }
284}
285
286impl std::fmt::Debug for ClientTlsOptions {
287 // Intentionally omit details here since they could leak a key if ever printed
288 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289 write!(f, "ClientTlsOptions(..)")
290 }
291}
292
293/// Options for starting a workflow execution.
294#[derive(Debug, Clone, bon::Builder)]
295#[builder(start_fn = new, on(String, into))]
296#[non_exhaustive]
297pub struct WorkflowStartOptions {
298 /// The task queue to run the workflow on.
299 #[builder(start_fn)]
300 pub task_queue: String,
301
302 /// The workflow ID.
303 #[builder(start_fn)]
304 pub workflow_id: String,
305
306 /// Set the policy for reusing the workflow id
307 #[builder(default)]
308 pub id_reuse_policy: WorkflowIdReusePolicy,
309
310 /// Set the policy for how to resolve conflicts with running policies.
311 /// NOTE: This is ignored for child workflows.
312 #[builder(default)]
313 pub id_conflict_policy: WorkflowIdConflictPolicy,
314
315 /// Optionally set the execution timeout for the workflow
316 /// <https://docs.temporal.io/workflows/#workflow-execution-timeout>
317 pub execution_timeout: Option<Duration>,
318
319 /// Optionally indicates the default run timeout for a workflow run
320 pub run_timeout: Option<Duration>,
321
322 /// Optionally indicates the default task timeout for a workflow run
323 pub task_timeout: Option<Duration>,
324
325 /// Optionally set a cron schedule for the workflow
326 pub cron_schedule: Option<String>,
327
328 /// Additional search attributes for the workflow.
329 pub search_attributes: Option<SearchAttributes>,
330
331 /// Optionally enable Eager Workflow Start, a latency optimization using local workers
332 /// NOTE: Experimental
333 #[builder(default)]
334 pub enable_eager_workflow_start: bool,
335
336 /// Optionally set a retry policy for the workflow
337 #[builder(into)]
338 pub retry_policy: Option<RetryPolicy>,
339
340 /// If set, send a signal to the workflow atomically with start.
341 /// The workflow will receive this signal before its first task.
342 pub start_signal: Option<WorkflowStartSignal>,
343
344 /// Links to associate with the workflow. Ex: References to a nexus operation.
345 #[builder(default)]
346 pub links: Vec<common::v1::Link>,
347
348 /// Callbacks that will be invoked upon workflow completion. For, ex, completing nexus
349 /// operations.
350 #[builder(default)]
351 pub completion_callbacks: Vec<common::v1::Callback>,
352
353 /// Priority for the workflow. Defaults to all-inherited (empty).
354 #[builder(default)]
355 pub priority: Priority,
356
357 /// Headers to include with the start request.
358 pub header: Option<Header>,
359
360 /// Single-line static summary for the workflow, shown in the Temporal UI.
361 pub static_summary: Option<String>,
362
363 /// Multi-line static details for the workflow, shown in the Temporal UI.
364 pub static_details: Option<String>,
365
366 /// Controls for the RPC used to start the workflow.
367 #[builder(default)]
368 pub rpc_options: RpcOptions,
369}
370
371/// A signal to send atomically when starting a workflow.
372/// Use with `WorkflowStartOptions::start_signal` to achieve signal-with-start behavior.
373#[derive(Debug, Clone, bon::Builder)]
374#[builder(start_fn = new, on(String, into))]
375#[non_exhaustive]
376pub struct WorkflowStartSignal {
377 /// Name of the signal to send.
378 #[builder(start_fn)]
379 pub signal_name: String,
380 /// Payload for the signal.
381 pub input: Option<Payloads>,
382 /// Headers for the signal.
383 pub header: Option<Header>,
384}
385
386pub use temporalio_common::Priority;
387
388/// Options for fetching workflow results
389#[derive(Debug, Clone, bon::Builder)]
390#[non_exhaustive]
391pub struct WorkflowGetResultOptions {
392 /// If true (the default), follows to the next workflow run in the execution chain while
393 /// retrieving results.
394 #[builder(default = true)]
395 pub follow_runs: bool,
396 /// Controls for each history RPC used to retrieve the result.
397 #[builder(default)]
398 pub rpc_options: RpcOptions,
399}
400impl Default for WorkflowGetResultOptions {
401 fn default() -> Self {
402 Self {
403 follow_runs: true,
404 rpc_options: RpcOptions::default(),
405 }
406 }
407}
408
409/// Options for starting a workflow update.
410#[derive(Debug, Clone, Default, bon::Builder)]
411#[non_exhaustive]
412pub struct WorkflowExecuteUpdateOptions {
413 /// Update ID for idempotency.
414 pub update_id: Option<String>,
415 /// Headers to include.
416 pub header: Option<Header>,
417 /// Controls for the start-update and poll-update RPCs.
418 #[builder(default)]
419 pub rpc_options: RpcOptions,
420}
421
422/// Options for sending a signal to a workflow.
423#[derive(Debug, Clone, Default, bon::Builder)]
424#[non_exhaustive]
425pub struct WorkflowSignalOptions {
426 /// Request ID for idempotency. If not provided, a UUID will be generated.
427 pub request_id: Option<String>,
428 /// Headers to include with the signal.
429 pub header: Option<Header>,
430 /// Controls for the signal RPC.
431 #[builder(default)]
432 pub rpc_options: RpcOptions,
433}
434
435/// Options for querying a workflow.
436#[derive(Debug, Clone, Default, bon::Builder)]
437#[non_exhaustive]
438pub struct WorkflowQueryOptions {
439 /// Query reject condition. Determines when the query should be rejected
440 /// based on workflow state.
441 pub reject_condition: Option<QueryRejectCondition>,
442 /// Headers to include with the query.
443 pub header: Option<Header>,
444 /// Controls for the query RPC.
445 #[builder(default)]
446 pub rpc_options: RpcOptions,
447}
448
449/// Options for cancelling a workflow.
450#[derive(Debug, Clone, Default, bon::Builder)]
451#[builder(on(String, into))]
452#[non_exhaustive]
453pub struct WorkflowCancelOptions {
454 /// Reason for cancellation.
455 #[builder(default)]
456 pub reason: String,
457 /// Request ID for idempotency. If not provided, a UUID will be generated.
458 pub request_id: Option<String>,
459 /// Controls for the cancellation RPC.
460 #[builder(default)]
461 pub rpc_options: RpcOptions,
462}
463
464/// Options for terminating a workflow.
465#[derive(Debug, Clone, Default, bon::Builder)]
466#[builder(on(String, into))]
467#[non_exhaustive]
468pub struct WorkflowTerminateOptions {
469 /// Reason for termination.
470 #[builder(default)]
471 pub reason: String,
472 /// Additional details to include with the termination.
473 pub details: Option<Payloads>,
474 /// Controls for the termination RPC.
475 #[builder(default)]
476 pub rpc_options: RpcOptions,
477}
478
479/// Options for describing a workflow.
480#[derive(Debug, Clone, Default, bon::Builder)]
481#[non_exhaustive]
482pub struct WorkflowDescribeOptions {
483 /// Controls for the describe RPC.
484 #[builder(default)]
485 pub rpc_options: RpcOptions,
486}
487
488/// Default workflow execution retention for a Namespace is 3 days
489const DEFAULT_WORKFLOW_EXECUTION_RETENTION_PERIOD: Duration = Duration::from_secs(60 * 60 * 24 * 3);
490
491/// Helper struct for `register_namespace`.
492#[derive(Clone, Debug, bon::Builder)]
493#[builder(on(String, into))]
494pub struct RegisterNamespaceOptions {
495 /// Name (required)
496 pub namespace: String,
497 /// Description (required)
498 pub description: String,
499 /// Owner's email
500 #[builder(default)]
501 pub owner_email: String,
502 /// Workflow execution retention period
503 #[builder(default = DEFAULT_WORKFLOW_EXECUTION_RETENTION_PERIOD)]
504 pub workflow_execution_retention_period: Duration,
505 /// Cluster settings
506 #[builder(default)]
507 pub clusters: Vec<ClusterReplicationConfig>,
508 /// Active cluster name
509 #[builder(default)]
510 pub active_cluster_name: String,
511 /// Custom Data
512 #[builder(default)]
513 pub data: HashMap<String, String>,
514 /// Security Token
515 #[builder(default)]
516 pub security_token: String,
517 /// Global namespace
518 #[builder(default)]
519 pub is_global_namespace: bool,
520 /// History Archival setting
521 #[builder(default = ArchivalState::Unspecified)]
522 pub history_archival_state: ArchivalState,
523 /// History Archival uri
524 #[builder(default)]
525 pub history_archival_uri: String,
526 /// Visibility Archival setting
527 #[builder(default = ArchivalState::Unspecified)]
528 pub visibility_archival_state: ArchivalState,
529 /// Visibility Archival uri
530 #[builder(default)]
531 pub visibility_archival_uri: String,
532}
533
534impl From<RegisterNamespaceOptions> for RegisterNamespaceRequest {
535 fn from(val: RegisterNamespaceOptions) -> Self {
536 RegisterNamespaceRequest {
537 namespace: val.namespace,
538 description: val.description,
539 owner_email: val.owner_email,
540 workflow_execution_retention_period: val
541 .workflow_execution_retention_period
542 .try_into()
543 .ok(),
544 clusters: val.clusters,
545 active_cluster_name: val.active_cluster_name,
546 data: val.data,
547 security_token: val.security_token,
548 is_global_namespace: val.is_global_namespace,
549 history_archival_state: val.history_archival_state as i32,
550 history_archival_uri: val.history_archival_uri,
551 visibility_archival_state: val.visibility_archival_state as i32,
552 visibility_archival_uri: val.visibility_archival_uri,
553 }
554 }
555}
556
557/// Options for fetching workflow history.
558#[derive(Debug, Clone, Default, bon::Builder)]
559#[non_exhaustive]
560pub struct WorkflowFetchHistoryOptions {
561 /// Whether to skip archival.
562 #[builder(default)]
563 pub skip_archival: bool,
564 /// If set true, the fetch will wait for a new event before returning.
565 #[builder(default)]
566 pub wait_new_event: bool,
567 /// Specifies which kind of events will be retrieved. Defaults to all events.
568 #[builder(default = HistoryEventFilterType::AllEvent)]
569 pub event_filter_type: HistoryEventFilterType,
570 /// Controls for each history page RPC.
571 #[builder(default)]
572 pub rpc_options: RpcOptions,
573}
574
575/// Which lifecycle stage to wait for when starting an update.
576#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
577pub enum WorkflowUpdateWaitStage {
578 /// This stage is reached when the server receives the update to process.
579 /// This is currently an invalid value on start.
580 Admitted,
581 /// Wait until the update is accepted by the workflow (validator passed).
582 #[default]
583 Accepted,
584 /// Wait until the update has completed.
585 Completed,
586}
587
588/// Options for starting an update without waiting for completion.
589#[derive(Debug, Clone, Default, bon::Builder)]
590#[non_exhaustive]
591pub struct WorkflowStartUpdateOptions {
592 /// Update ID for idempotency. If not provided, a UUID will be generated.
593 pub update_id: Option<String>,
594 /// Headers to include with the update.
595 pub header: Option<Header>,
596 /// The lifecycle stage to wait for before returning the handle.
597 #[builder(default)]
598 pub wait_for_stage: WorkflowUpdateWaitStage,
599 /// Controls for the start-update RPC.
600 #[builder(default)]
601 pub rpc_options: RpcOptions,
602}
603
604/// Options for listing workflows.
605#[derive(Debug, Clone, Default, bon::Builder)]
606#[non_exhaustive]
607pub struct WorkflowListOptions {
608 /// Maximum number of workflows to return.
609 /// If not specified, returns all matching workflows.
610 pub limit: Option<usize>,
611 /// Controls for each list page RPC.
612 #[builder(default)]
613 pub rpc_options: RpcOptions,
614}
615
616/// Options for counting workflows.
617#[derive(Debug, Clone, Default, bon::Builder)]
618#[non_exhaustive]
619pub struct WorkflowCountOptions {
620 /// Controls for the count RPC.
621 #[builder(default)]
622 pub rpc_options: RpcOptions,
623}