Skip to main content

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}