Skip to main content

temporalio_client/
options_structs.rs

1use crate::{
2    ClientInterceptor, HttpConnectProxyOptions, RetryOptions, RpcOptions, VERSION, callback_based,
3};
4#[cfg(feature = "experimental")]
5use crate::{ClientPlugin, ErasedClientPlugin};
6use http::Uri;
7use std::{collections::HashMap, sync::Arc, time::Duration};
8use temporalio_common::{
9    ActivityCloseTimeouts, MemoValues, RetryPolicy,
10    data_converters::{
11        DataConverter, GenericPayloadConverter, PayloadConversionError, PayloadConverter,
12        SerializationContext, SerializationContextData, WorkflowSerializationContext,
13    },
14    payload_visitor::encode_payloads,
15    protos::temporal::api::{
16        common::{
17            self,
18            v1::{Header, Memo as ProtoMemo, Payloads},
19        },
20        enums::v1::{
21            ActivityIdConflictPolicy as ProtoActivityIdConflictPolicy,
22            ActivityIdReusePolicy as ProtoActivityIdReusePolicy, ArchivalState,
23            HistoryEventFilterType, QueryRejectCondition, WorkflowIdConflictPolicy,
24            WorkflowIdReusePolicy,
25        },
26        replication::v1::ClusterReplicationConfig,
27        sdk::v1::UserMetadata,
28        workflowservice::v1::RegisterNamespaceRequest,
29    },
30    search_attributes::SearchAttributes,
31    telemetry::metrics::TemporalMeter,
32};
33#[cfg(feature = "dynamic-tls")]
34use tokio_rustls::rustls::client::ResolvesClientCert;
35use tokio_rustls::rustls::client::danger::ServerCertVerifier;
36use url::Url;
37
38pub(crate) const DEFAULT_PAYLOADS_WARN_SIZE: u64 = 512 * 1024;
39pub(crate) const DEFAULT_MEMO_WARN_SIZE: u64 = 2 * 1024;
40
41/// Options for [crate::Connection::connect].
42#[derive(bon::Builder, Clone, Debug)]
43#[non_exhaustive]
44#[builder(start_fn = new, on(String, into), state_mod(vis = "pub"))]
45pub struct ConnectionOptions {
46    /// The server to connect to.
47    #[builder(start_fn, into)]
48    pub target: Url,
49    /// A human-readable string that can identify this process. Defaults to empty string.
50    #[builder(default)]
51    pub identity: String,
52    /// When set, this client will record metrics using the provided meter. The meter can be
53    /// obtained from [temporalio_common::telemetry::TelemetryInstance::get_temporal_metric_meter].
54    pub metrics_meter: Option<TemporalMeter>,
55    /// If specified, use TLS as configured by the [TlsOptions] struct. If this is set core will
56    /// attempt to use TLS when connecting to the Temporal server. Lang SDK is expected to pass any
57    /// certs or keys as bytes, loading them from disk itself if needed.
58    pub tls_options: Option<TlsOptions>,
59    /// If set, override the origin used when connecting. May be useful in rare situations where tls
60    /// verification needs to use a different name from what should be set as the `:authority`
61    /// header. If [TlsOptions::domain] is set, and this is not, this will be set to
62    /// `https://<domain>`, effectively making the `:authority` header consistent with the domain
63    /// override.
64    pub override_origin: Option<Uri>,
65    /// An API key to use for auth. If set, TLS will be enabled by default, but without any mTLS
66    /// specific settings.
67    pub api_key: Option<String>,
68    /// When set, limits the time allowed to establish the initial TCP/TLS connection to the
69    /// server. If the connection cannot be established within this duration, `connect` will
70    /// return an error. When `None` (the default), no explicit timeout is applied and the
71    /// connection attempt may block indefinitely (subject to OS-level TCP timeouts).
72    pub connect_timeout: Option<Duration>,
73    /// Retry configuration for the server client. Default is [RetryOptions::default]
74    #[builder(default)]
75    pub retry_options: RetryOptions,
76    /// If set, HTTP2 gRPC keep alive will be enabled.
77    /// To enable with default settings, use `.keep_alive(Some(ClientKeepAliveConfig::default()))`.
78    #[builder(required, default = Some(ClientKeepAliveOptions::default()))]
79    pub keep_alive: Option<ClientKeepAliveOptions>,
80    /// HTTP headers to include on every RPC call.
81    ///
82    /// These must be valid gRPC metadata keys, and must not be binary metadata keys (ending in
83    /// `-bin). To set binary headers, use [ConnectionOptions::binary_headers]. Invalid header keys
84    /// or values will cause an error to be returned when connecting.
85    pub headers: Option<HashMap<String, String>>,
86    /// HTTP headers to include on every RPC call as binary gRPC metadata (encoded as base64).
87    ///
88    /// These must be valid binary gRPC metadata keys (and end with a `-bin` suffix). Invalid
89    /// header keys will cause an error to be returned when connecting.
90    pub binary_headers: Option<HashMap<String, Vec<u8>>>,
91    /// HTTP CONNECT proxy to use for this client.
92    pub http_connect_proxy: Option<HttpConnectProxyOptions>,
93    /// If set, DNS-based load balancing is enabled. When the target is a hostname (not an IP
94    /// literal), DNS is resolved to all addresses and requests are distributed across them.
95    /// Incompatible with `service_override` and `http_connect_proxy`. Setting either in addition
96    /// to this field is an error. Set to `None` to disable.
97    #[builder(required, default = Some(DnsLoadBalancingOptions::default()))]
98    pub dns_load_balancing: Option<DnsLoadBalancingOptions>,
99    /// If set true, error code labels will not be included on request failure metrics.
100    #[builder(default)]
101    pub disable_error_code_metric_tags: bool,
102    /// If set, all gRPC calls will be routed through the provided service.
103    pub service_override: Option<callback_based::CallbackBasedGrpcService>,
104    /// Controls transport-level gRPC compression for the client. Defaults to
105    /// [GrpcCompression::Gzip], which compresses outbound request bodies and accepts
106    /// compressed responses. Set to [GrpcCompression::None] to opt out.
107    /// If service_override is specified, is forced to `None`.
108    #[builder(default)]
109    pub grpc_compression: GrpcCompression,
110    /// Payload size limit options for this connection. Defaults to the standard warning thresholds;
111    /// disable an individual warning by setting its threshold to `0`.
112    /// NOTE: Experimental
113    #[cfg(feature = "experimental")]
114    #[cfg_attr(
115        docsrs,
116        builder(setters(
117            some_fn(name = payload_limits_impl, vis = "pub(crate)"),
118            option_fn(name = maybe_payload_limits_impl, vis = "pub(crate)")
119        ))
120    )]
121    #[builder(default)]
122    pub payload_limits: PayloadLimitsOptions,
123
124    // Internal / Core-based SDK only options below =============================================
125    /// If set true, get_system_info will not be called upon connection.
126    #[builder(default)]
127    #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
128    pub(crate) skip_get_system_info: bool,
129    /// The name of the SDK being implemented on top of core. Is set as `client-name` header in
130    /// all RPC calls
131    #[builder(default = "temporal-rust".to_owned())]
132    #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
133    pub(crate) client_name: String,
134    // TODO [rust-sdk-branch]: SDK should set this to its version. Doing that probably easiest
135    // after adding proper client interceptors.
136    /// The version of the SDK being implemented on top of core. Is set as `client-version` header
137    /// in all RPC calls. The server decides if the client is supported based on this.
138    #[builder(default = VERSION.to_owned())]
139    #[cfg_attr(feature = "core-based-sdk", builder(setters(vis = "pub")))]
140    pub(crate) client_version: String,
141}
142
143// Bon does not propagate `doc(cfg)` to generated setters, so these docs-only methods forward to
144// renamed generated implementations.
145#[cfg(all(feature = "experimental", docsrs))]
146impl<S: connection_options_builder::State> ConnectionOptionsBuilder<S> {
147    /// Set the payload size limit options for this connection.
148    #[doc(cfg(feature = "experimental"))]
149    pub fn payload_limits(
150        self,
151        value: PayloadLimitsOptions,
152    ) -> ConnectionOptionsBuilder<connection_options_builder::SetPayloadLimits<S>>
153    where
154        S::PayloadLimits: connection_options_builder::IsUnset,
155    {
156        self.payload_limits_impl(value)
157    }
158
159    /// Set the payload size limit options for this connection from an optional value.
160    #[doc(cfg(feature = "experimental"))]
161    pub fn maybe_payload_limits(
162        self,
163        value: Option<PayloadLimitsOptions>,
164    ) -> ConnectionOptionsBuilder<connection_options_builder::SetPayloadLimits<S>>
165    where
166        S::PayloadLimits: connection_options_builder::IsUnset,
167    {
168        self.maybe_payload_limits_impl(value)
169    }
170}
171
172// Setters/getters for fields that should only be touched by SDK implementers.
173#[cfg(feature = "core-based-sdk")]
174impl ConnectionOptions {
175    /// Set whether or not get_system_info will be called upon connection.
176    pub fn set_skip_get_system_info(&mut self, skip: bool) {
177        self.skip_get_system_info = skip;
178    }
179    /// Get whether or not get_system_info will be called upon connection.
180    pub fn get_skip_get_system_info(&self) -> bool {
181        self.skip_get_system_info
182    }
183    /// Get the name of the SDK being implemented on top of core.
184    pub fn get_client_name(&self) -> &str {
185        &self.client_name
186    }
187    /// Get the version of the SDK being implemented on top of core.
188    pub fn get_client_version(&self) -> &str {
189        &self.client_version
190    }
191}
192
193/// Options for [crate::Client::new].
194#[derive(Clone, derive_more::Debug, bon::Builder)]
195#[non_exhaustive]
196#[builder(start_fn = new, on(String, into), state_mod(vis = "pub"))]
197pub struct ClientOptions {
198    /// The namespace this client will be bound to.
199    #[builder(start_fn)]
200    pub namespace: String,
201
202    #[builder(field)]
203    #[debug(skip)]
204    #[cfg(feature = "experimental")]
205    plugins: Vec<ErasedClientPlugin>,
206
207    #[builder(field)]
208    #[debug(skip)]
209    #[cfg(feature = "experimental")]
210    client_plugins_applied: bool,
211
212    /// The data converter used for serializing/deserializing payloads.
213    #[builder(default)]
214    pub data_converter: DataConverter,
215    /// Interceptors for high-level client operations, ordered outermost to innermost.
216    #[builder(default)]
217    #[debug(skip)]
218    pub client_interceptors: Vec<Arc<dyn ClientInterceptor>>,
219}
220
221#[cfg(feature = "experimental")]
222impl<S: client_options_builder::State> ClientOptionsBuilder<S> {
223    /// Register a type-erased client plugin.
224    ///
225    /// **Experimental:** This API may change or be removed.
226    pub fn plugin<P: Into<ErasedClientPlugin>>(mut self, plugin: P) -> Self {
227        self.plugins.push(plugin.into());
228        self
229    }
230
231    /// Register type-erased client plugins in iteration order.
232    ///
233    /// **Experimental:** This API may change or be removed.
234    pub fn plugins<I, P>(mut self, plugins: I) -> Self
235    where
236        I: IntoIterator<Item = P>,
237        P: Into<ErasedClientPlugin>,
238    {
239        self.plugins.extend(plugins.into_iter().map(Into::into));
240        self
241    }
242
243    /// Register a client-only plugin.
244    ///
245    /// **Experimental:** This API may change or be removed.
246    pub fn client_plugin<P: ClientPlugin>(mut self, plugin: P) -> Self {
247        self.plugins.push(ErasedClientPlugin::new(plugin));
248        self
249    }
250}
251
252impl ClientOptions {
253    /// Return the registered plugins.
254    ///
255    /// This is intended for SDK integrations that propagate worker plugin registrations.
256    ///
257    /// **Experimental:** This API may change or be removed.
258    #[cfg(feature = "experimental")]
259    pub fn plugins(&self) -> &[ErasedClientPlugin] {
260        &self.plugins
261    }
262
263    #[cfg(feature = "experimental")]
264    pub(crate) fn client_plugins_applied(&self) -> bool {
265        self.client_plugins_applied
266    }
267
268    #[cfg(feature = "experimental")]
269    pub(crate) fn mark_client_plugins_applied(&mut self) {
270        self.client_plugins_applied = true;
271    }
272}
273
274/// Selects the transport-level compression used for gRPC calls. See
275/// [ConnectionOptions::grpc_compression].
276#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
277#[non_exhaustive]
278pub enum GrpcCompression {
279    /// Do not compress requests or advertise acceptance of compressed responses.
280    None,
281    /// Gzip-compress outbound requests and accept gzip-compressed responses.
282    #[default]
283    Gzip,
284}
285
286/// Configuration options for TLS
287#[derive(Clone, bon::Builder)]
288#[non_exhaustive]
289pub struct TlsOptions {
290    /// Bytes representing the root CA certificate used by the server. If not set, and the server's
291    /// cert is issued by someone the operating system trusts, verification will still work (ex:
292    /// Cloud offering).
293    pub server_root_ca_cert: Option<Vec<u8>>,
294    /// Sets the domain name against which to verify the server's TLS certificate. If not provided,
295    /// the domain name will be extracted from the URL used to connect.
296    pub domain: Option<String>,
297    /// TLS info for the client. If specified, core will attempt to use mTLS.
298    ///
299    /// Mutually exclusive with [`client_cert_resolver`](TlsOptions::client_cert_resolver).
300    /// Setting both is an error.
301    pub client_tls_options: Option<ClientTlsOptions>,
302    /// Optional custom server certificate verifier. When set, this replaces the default
303    /// certificate verification and `server_root_ca_cert` is ignored.
304    ///
305    /// This is useful for:
306    /// - Certificate pinning
307    /// - Custom trust-domain validation (e.g., SAN-URI extraction)
308    /// - Federated root certificate stores
309    ///
310    /// # WARNING
311    /// Implementing a custom `ServerCertVerifier` can lead to severely insecure TLS connections
312    /// (e.g., disabling all validation or allowing man-in-the-middle attacks) if not done carefully.
313    /// Only use this if you know exactly what you are doing.
314    ///
315    /// The verifier must implement [`ServerCertVerifier`] from the `rustls` crate.
316    /// Note that `domain` is still respected for the `:authority` header / origin override
317    /// even when a custom verifier is set.
318    pub server_cert_verifier: Option<Arc<dyn ServerCertVerifier>>,
319    /// Optional dynamic client certificate resolver for transparent mTLS certificate rotation.
320    ///
321    /// Mutually exclusive with [`client_tls_options`](TlsOptions::client_tls_options).
322    /// Setting both is an error.
323    #[cfg(feature = "dynamic-tls")]
324    pub client_cert_resolver: Option<Arc<dyn ResolvesClientCert>>,
325}
326
327impl Default for TlsOptions {
328    fn default() -> Self {
329        Self::builder().build()
330    }
331}
332
333impl std::fmt::Debug for TlsOptions {
334    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335        let mut s = f.debug_struct("TlsOptions");
336        s.field(
337            "server_root_ca_cert",
338            &self
339                .server_root_ca_cert
340                .as_ref()
341                .map(|c| format!("{} bytes", c.len())),
342        );
343        s.field("domain", &self.domain);
344        s.field("client_tls_options", &self.client_tls_options);
345        s.field(
346            "server_cert_verifier",
347            &self.server_cert_verifier.as_ref().map(|_| "<custom>"),
348        );
349        #[cfg(feature = "dynamic-tls")]
350        s.field(
351            "client_cert_resolver",
352            &self.client_cert_resolver.as_ref().map(|_| "<custom>"),
353        );
354        s.finish()
355    }
356}
357
358/// If using mTLS, both the client cert and private key must be specified, this contains them.
359#[derive(Clone, bon::Builder)]
360#[non_exhaustive]
361pub struct ClientTlsOptions {
362    /// The certificate for this client, encoded as PEM
363    pub client_cert: Vec<u8>,
364    /// The private key for this client, encoded as PEM
365    pub client_private_key: Vec<u8>,
366}
367
368/// Client keep alive configuration.
369#[derive(Clone, Debug, PartialEq, bon::Builder)]
370#[non_exhaustive]
371pub struct ClientKeepAliveOptions {
372    /// Interval to send HTTP2 keep alive pings.
373    #[builder(default = Duration::from_secs(30))]
374    pub interval: Duration,
375    /// Timeout that the keep alive must be responded to within or the connection will be closed.
376    #[builder(default = Duration::from_secs(15))]
377    pub timeout: Duration,
378}
379
380impl Default for ClientKeepAliveOptions {
381    fn default() -> Self {
382        Self::builder().build()
383    }
384}
385
386/// Options for DNS-based load balancing.
387#[derive(Clone, Debug, PartialEq, bon::Builder)]
388#[non_exhaustive]
389pub struct DnsLoadBalancingOptions {
390    /// How often to re-resolve DNS. Defaults to 30 seconds.
391    #[builder(default = Duration::from_secs(30))]
392    pub resolution_interval: Duration,
393}
394
395impl Default for DnsLoadBalancingOptions {
396    fn default() -> Self {
397        Self::builder().build()
398    }
399}
400
401/// Payload size limit options for a connection.
402/// NOTE: Experimental
403#[cfg(feature = "experimental")]
404#[derive(Clone, Debug, PartialEq, bon::Builder)]
405#[non_exhaustive]
406pub struct PayloadLimitsOptions {
407    /// Warning threshold (bytes) for the size of an outbound payload-bearing field; over-threshold
408    /// fields are logged but still sent to server. Defaults to 512 KiB. Set to `0` to disable.
409    #[builder(default = DEFAULT_PAYLOADS_WARN_SIZE)]
410    pub payloads_warn_size: u64,
411    /// Warning threshold (bytes) for outbound memo sizes; over-threshold memos are logged but still
412    /// sent to server. Defaults to 2 KiB. Set to `0` to disable.
413    #[builder(default = DEFAULT_MEMO_WARN_SIZE)]
414    pub memo_warn_size: u64,
415}
416
417#[cfg(feature = "experimental")]
418impl Default for PayloadLimitsOptions {
419    fn default() -> Self {
420        Self::builder().build()
421    }
422}
423
424impl std::fmt::Debug for ClientTlsOptions {
425    // Intentionally omit details here since they could leak a key if ever printed
426    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427        write!(f, "ClientTlsOptions(..)")
428    }
429}
430
431/// Options for starting a workflow execution.
432#[derive(Debug, Clone, bon::Builder)]
433#[builder(start_fn = new, on(String, into))]
434#[non_exhaustive]
435pub struct WorkflowStartOptions {
436    /// The task queue to run the workflow on.
437    #[builder(start_fn)]
438    pub task_queue: String,
439
440    /// The workflow ID.
441    #[builder(start_fn)]
442    pub workflow_id: String,
443
444    /// Set the policy for reusing the workflow id
445    #[builder(default)]
446    pub id_reuse_policy: WorkflowIdReusePolicy,
447
448    /// Set the policy for how to resolve conflicts with running policies.
449    /// NOTE: This is ignored for child workflows.
450    #[builder(default)]
451    pub id_conflict_policy: WorkflowIdConflictPolicy,
452
453    /// Optionally set the execution timeout for the workflow
454    /// <https://docs.temporal.io/workflows/#workflow-execution-timeout>
455    pub execution_timeout: Option<Duration>,
456
457    /// Optionally indicates the default run timeout for a workflow run
458    pub run_timeout: Option<Duration>,
459
460    /// Optionally indicates the default task timeout for a workflow run
461    pub task_timeout: Option<Duration>,
462
463    /// Optionally set a cron schedule for the workflow
464    pub cron_schedule: Option<String>,
465
466    /// Additional search attributes for the workflow.
467    pub search_attributes: Option<SearchAttributes>,
468
469    /// Optionally enable Eager Workflow Start, a latency optimization using local workers.
470    #[builder(default)]
471    pub enable_eager_workflow_start: bool,
472
473    /// Optionally set a retry policy for the workflow
474    #[builder(into)]
475    pub retry_policy: Option<RetryPolicy>,
476
477    /// Links to associate with the workflow. Ex: References to a nexus operation.
478    #[builder(default)]
479    pub links: Vec<common::v1::Link>,
480
481    /// Callbacks that will be invoked upon workflow completion. For, ex, completing nexus
482    /// operations.
483    #[builder(default)]
484    pub completion_callbacks: Vec<common::v1::Callback>,
485
486    /// Priority for the workflow. Defaults to all-inherited (empty).
487    #[builder(default)]
488    pub priority: Priority,
489
490    /// Headers to include with the start request.
491    pub header: Option<Header>,
492
493    /// Non-indexed values attached to the workflow, serialized with the client's data converter.
494    pub memo: Option<MemoValues>,
495
496    /// Single-line static summary for the workflow, shown in the Temporal UI.
497    pub static_summary: Option<String>,
498
499    /// Multi-line static details for the workflow, shown in the Temporal UI.
500    pub static_details: Option<String>,
501
502    /// Controls for the RPC used to start the workflow.
503    #[builder(default)]
504    pub rpc_options: RpcOptions,
505}
506
507impl WorkflowStartOptions {
508    pub(crate) async fn encoded_memo(
509        &self,
510        data_converter: &DataConverter,
511    ) -> Result<Option<ProtoMemo>, PayloadConversionError> {
512        let Some(memo) = &self.memo else {
513            return Ok(None);
514        };
515
516        let payload_converter = data_converter.payload_converter();
517        let context_data = SerializationContextData::Workflow(WorkflowSerializationContext::new());
518        let context = SerializationContext::new(&context_data, payload_converter);
519        let mut memo = ProtoMemo {
520            fields: memo
521                .iter()
522                .map(|(key, value)| {
523                    payload_converter
524                        .to_payload(&context, value)
525                        .map(|payload| (key.to_owned(), payload))
526                })
527                .collect::<Result<_, _>>()?,
528        };
529        encode_payloads(
530            &mut memo,
531            data_converter.codec(),
532            &SerializationContextData::Workflow(WorkflowSerializationContext::new()),
533        )
534        .await?;
535        Ok(Some(memo))
536    }
537
538    pub(crate) fn user_metadata(&self) -> Option<UserMetadata> {
539        (self.static_summary.is_some() || self.static_details.is_some()).then(|| {
540            let payload_converter = PayloadConverter::default();
541            let context_data =
542                SerializationContextData::Workflow(WorkflowSerializationContext::new());
543            let context = SerializationContext::new(&context_data, &payload_converter);
544            UserMetadata {
545                summary: self.static_summary.as_ref().map(|summary| {
546                    payload_converter
547                        .to_payload(&context, summary)
548                        .expect("String-to-JSON payload serialization is infallible")
549                }),
550                details: self.static_details.as_ref().map(|details| {
551                    payload_converter
552                        .to_payload(&context, details)
553                        .expect("String-to-JSON payload serialization is infallible")
554                }),
555            }
556        })
557    }
558}
559
560/// Options for starting a workflow and sending it an update in one atomic operation.
561///
562/// See [crate::Client::start_update_with_start_workflow] and
563/// [crate::Client::execute_update_with_start_workflow].
564#[derive(Debug, Clone, bon::Builder)]
565#[builder(start_fn = new, on(String, into))]
566#[non_exhaustive]
567pub struct WorkflowUpdateWithStartOptions {
568    /// The task queue to run the workflow on.
569    #[builder(start_fn)]
570    pub task_queue: String,
571
572    /// The workflow ID.
573    #[builder(start_fn)]
574    pub workflow_id: String,
575
576    /// How to resolve a conflict with an already-running workflow. This is required so callers
577    /// explicitly choose whether an update may attach to an existing workflow.
578    #[builder(start_fn)]
579    pub id_conflict_policy: WorkflowIdConflictPolicy,
580
581    /// The policy for reusing the workflow ID after a workflow closes.
582    #[builder(default)]
583    pub id_reuse_policy: WorkflowIdReusePolicy,
584
585    /// The workflow execution timeout.
586    pub execution_timeout: Option<Duration>,
587
588    /// The workflow run timeout.
589    pub run_timeout: Option<Duration>,
590
591    /// The workflow task timeout.
592    pub task_timeout: Option<Duration>,
593
594    /// Search attributes for the workflow.
595    pub search_attributes: Option<SearchAttributes>,
596
597    /// The workflow retry policy.
598    #[builder(into)]
599    pub retry_policy: Option<RetryPolicy>,
600
601    /// Links to associate with the workflow.
602    #[builder(default)]
603    pub links: Vec<common::v1::Link>,
604
605    /// Callbacks invoked when the workflow completes.
606    #[builder(default)]
607    pub completion_callbacks: Vec<common::v1::Callback>,
608
609    /// Priority for the workflow. Defaults to all-inherited (empty).
610    #[builder(default)]
611    pub priority: Priority,
612
613    /// Headers to include with the start operation.
614    pub start_header: Option<Header>,
615
616    /// Headers to include with the update operation.
617    pub update_header: Option<Header>,
618
619    /// Non-indexed values attached to the workflow, serialized with the client's data converter.
620    pub memo: Option<MemoValues>,
621
622    /// Single-line static summary for the workflow, shown in the Temporal UI.
623    pub static_summary: Option<String>,
624
625    /// Multi-line static details for the workflow, shown in the Temporal UI.
626    pub static_details: Option<String>,
627
628    /// Update ID for idempotency. If not provided, a UUID will be generated.
629    pub update_id: Option<String>,
630
631    /// Controls for the multi-operation RPC and, when executing the update, subsequent polling.
632    #[builder(default)]
633    pub rpc_options: RpcOptions,
634}
635
636impl WorkflowUpdateWithStartOptions {
637    pub(crate) fn into_parts(self) -> (WorkflowStartOptions, Option<String>, Option<Header>) {
638        let Self {
639            task_queue,
640            workflow_id,
641            id_conflict_policy,
642            id_reuse_policy,
643            execution_timeout,
644            run_timeout,
645            task_timeout,
646            search_attributes,
647            retry_policy,
648            links,
649            completion_callbacks,
650            priority,
651            start_header,
652            update_header,
653            memo,
654            static_summary,
655            static_details,
656            update_id,
657            rpc_options: _,
658        } = self;
659        (
660            WorkflowStartOptions {
661                task_queue,
662                workflow_id,
663                id_reuse_policy,
664                id_conflict_policy,
665                execution_timeout,
666                run_timeout,
667                task_timeout,
668                cron_schedule: None,
669                search_attributes,
670                enable_eager_workflow_start: false,
671                retry_policy,
672                links,
673                completion_callbacks,
674                priority,
675                header: start_header,
676                memo,
677                static_summary,
678                static_details,
679                rpc_options: RpcOptions::default(),
680            },
681            update_id,
682            update_header,
683        )
684    }
685}
686
687pub use temporalio_common::Priority;
688
689/// Options for fetching workflow results
690#[derive(Debug, Clone, bon::Builder)]
691#[non_exhaustive]
692pub struct WorkflowGetResultOptions {
693    /// If true (the default), follows to the next workflow run in the execution chain while
694    /// retrieving results.
695    #[builder(default = true)]
696    pub follow_runs: bool,
697    /// Controls for each history RPC used to retrieve the result.
698    #[builder(default)]
699    pub rpc_options: RpcOptions,
700}
701impl Default for WorkflowGetResultOptions {
702    fn default() -> Self {
703        Self {
704            follow_runs: true,
705            rpc_options: RpcOptions::default(),
706        }
707    }
708}
709
710/// Options for starting a workflow update.
711#[derive(Debug, Clone, Default, bon::Builder)]
712#[non_exhaustive]
713pub struct WorkflowExecuteUpdateOptions {
714    /// Update ID for idempotency.
715    pub update_id: Option<String>,
716    /// Headers to include.
717    pub header: Option<Header>,
718    /// Controls for the start-update and poll-update RPCs.
719    #[builder(default)]
720    pub rpc_options: RpcOptions,
721}
722
723/// Options for sending a signal to a workflow.
724#[derive(Debug, Clone, Default, bon::Builder)]
725#[non_exhaustive]
726pub struct WorkflowSignalOptions {
727    /// Request ID for idempotency. If not provided, a UUID will be generated.
728    pub request_id: Option<String>,
729    /// Headers to include with the signal.
730    pub header: Option<Header>,
731    /// Controls for the signal RPC.
732    #[builder(default)]
733    pub rpc_options: RpcOptions,
734}
735
736/// Options for querying a workflow.
737#[derive(Debug, Clone, Default, bon::Builder)]
738#[non_exhaustive]
739pub struct WorkflowQueryOptions {
740    /// Query reject condition. Determines when the query should be rejected
741    /// based on workflow state.
742    pub reject_condition: Option<QueryRejectCondition>,
743    /// Headers to include with the query.
744    pub header: Option<Header>,
745    /// Controls for the query RPC.
746    #[builder(default)]
747    pub rpc_options: RpcOptions,
748}
749
750/// Options for cancelling a workflow.
751#[derive(Debug, Clone, Default, bon::Builder)]
752#[builder(on(String, into))]
753#[non_exhaustive]
754pub struct WorkflowCancelOptions {
755    /// Reason for cancellation.
756    #[builder(default)]
757    pub reason: String,
758    /// Request ID for idempotency. If not provided, a UUID will be generated.
759    pub request_id: Option<String>,
760    /// Controls for the cancellation RPC.
761    #[builder(default)]
762    pub rpc_options: RpcOptions,
763}
764
765/// Options for terminating a workflow.
766#[derive(Debug, Clone, Default, bon::Builder)]
767#[builder(on(String, into))]
768#[non_exhaustive]
769pub struct WorkflowTerminateOptions {
770    /// Reason for termination.
771    #[builder(default)]
772    pub reason: String,
773    /// Additional details to include with the termination.
774    pub details: Option<Payloads>,
775    /// Controls for the termination RPC.
776    #[builder(default)]
777    pub rpc_options: RpcOptions,
778}
779
780/// Options for describing a workflow.
781#[derive(Debug, Clone, Default, bon::Builder)]
782#[non_exhaustive]
783pub struct WorkflowDescribeOptions {
784    /// Controls for the describe RPC.
785    #[builder(default)]
786    pub rpc_options: RpcOptions,
787}
788
789/// Default workflow execution retention for a Namespace is 3 days
790const DEFAULT_WORKFLOW_EXECUTION_RETENTION_PERIOD: Duration = Duration::from_secs(60 * 60 * 24 * 3);
791
792/// Helper struct for `register_namespace`.
793#[derive(Clone, Debug, bon::Builder)]
794#[builder(on(String, into))]
795#[non_exhaustive]
796pub struct RegisterNamespaceOptions {
797    /// Name (required)
798    pub namespace: String,
799    /// Description (required)
800    pub description: String,
801    /// Owner's email
802    #[builder(default)]
803    pub owner_email: String,
804    /// Workflow execution retention period
805    #[builder(default = DEFAULT_WORKFLOW_EXECUTION_RETENTION_PERIOD)]
806    pub workflow_execution_retention_period: Duration,
807    /// Cluster settings
808    #[builder(default)]
809    pub clusters: Vec<ClusterReplicationConfig>,
810    /// Active cluster name
811    #[builder(default)]
812    pub active_cluster_name: String,
813    /// Custom Data
814    #[builder(default)]
815    pub data: HashMap<String, String>,
816    /// Security Token
817    #[builder(default)]
818    pub security_token: String,
819    /// Global namespace
820    #[builder(default)]
821    pub is_global_namespace: bool,
822    /// History Archival setting
823    #[builder(default = ArchivalState::Unspecified)]
824    pub history_archival_state: ArchivalState,
825    /// History Archival uri
826    #[builder(default)]
827    pub history_archival_uri: String,
828    /// Visibility Archival setting
829    #[builder(default = ArchivalState::Unspecified)]
830    pub visibility_archival_state: ArchivalState,
831    /// Visibility Archival uri
832    #[builder(default)]
833    pub visibility_archival_uri: String,
834}
835
836impl From<RegisterNamespaceOptions> for RegisterNamespaceRequest {
837    fn from(val: RegisterNamespaceOptions) -> Self {
838        RegisterNamespaceRequest {
839            namespace: val.namespace,
840            description: val.description,
841            owner_email: val.owner_email,
842            workflow_execution_retention_period: val
843                .workflow_execution_retention_period
844                .try_into()
845                .ok(),
846            clusters: val.clusters,
847            active_cluster_name: val.active_cluster_name,
848            data: val.data,
849            security_token: val.security_token,
850            is_global_namespace: val.is_global_namespace,
851            history_archival_state: val.history_archival_state as i32,
852            history_archival_uri: val.history_archival_uri,
853            visibility_archival_state: val.visibility_archival_state as i32,
854            visibility_archival_uri: val.visibility_archival_uri,
855        }
856    }
857}
858
859/// Options for fetching workflow history.
860#[derive(Debug, Clone, Default, bon::Builder)]
861#[non_exhaustive]
862pub struct WorkflowFetchHistoryOptions {
863    /// Whether to skip archival.
864    #[builder(default)]
865    pub skip_archival: bool,
866    /// If set true, the fetch will wait for a new event before returning.
867    #[builder(default)]
868    pub wait_new_event: bool,
869    /// Specifies which kind of events will be retrieved. Defaults to all events.
870    #[builder(default = HistoryEventFilterType::AllEvent)]
871    pub event_filter_type: HistoryEventFilterType,
872    /// Controls for each history page RPC.
873    #[builder(default)]
874    pub rpc_options: RpcOptions,
875}
876
877/// Options for starting an update without waiting for completion.
878#[derive(Debug, Clone, Default, bon::Builder)]
879#[non_exhaustive]
880pub struct WorkflowStartUpdateOptions {
881    /// Update ID for idempotency. If not provided, a UUID will be generated.
882    pub update_id: Option<String>,
883    /// Headers to include with the update.
884    pub header: Option<Header>,
885    /// Controls for the start-update RPC.
886    #[builder(default)]
887    pub rpc_options: RpcOptions,
888}
889
890impl From<WorkflowExecuteUpdateOptions> for WorkflowStartUpdateOptions {
891    /// Execute-update is start-update followed by waiting for the update result.
892    fn from(options: WorkflowExecuteUpdateOptions) -> Self {
893        Self::builder()
894            .maybe_update_id(options.update_id)
895            .maybe_header(options.header)
896            .rpc_options(options.rpc_options)
897            .build()
898    }
899}
900
901/// Options for listing workflows.
902#[derive(Debug, Clone, Default, bon::Builder)]
903#[non_exhaustive]
904pub struct WorkflowListOptions {
905    /// Maximum number of workflows to return.
906    /// If not specified, returns all matching workflows.
907    pub limit: Option<usize>,
908    /// Controls for each list page RPC.
909    #[builder(default)]
910    pub rpc_options: RpcOptions,
911}
912
913/// Options for counting workflows.
914#[derive(Debug, Clone, Default, bon::Builder)]
915#[non_exhaustive]
916pub struct WorkflowCountOptions {
917    /// Controls for the count RPC.
918    #[builder(default)]
919    pub rpc_options: RpcOptions,
920}
921
922/// Options for starting a standalone activity.
923#[derive(Clone, Debug, bon::Builder)]
924#[builder(start_fn = new, on(String, into))]
925#[non_exhaustive]
926pub struct ActivityStartOptions {
927    /// Task queue to run this activity on.
928    #[builder(start_fn)]
929    pub task_queue: String,
930    /// Activity ID of the started activity. It's recommended to use a meaningful business ID.
931    #[builder(start_fn)]
932    pub id: String,
933    /// Timeouts for activity completion.
934    ///
935    /// See [`ActivityCloseTimeouts`] for the meaning of each timeout variant.
936    #[builder(start_fn)]
937    pub close_timeouts: ActivityCloseTimeouts,
938    /// If set, specifies maximum time the activity can wait in the task queue before being picked
939    /// up by a worker. This timeout is non-retryable.
940    pub schedule_to_start_timeout: Option<Duration>,
941    /// If set, specifies maximum time between successful heartbeats.
942    pub heartbeat_timeout: Option<Duration>,
943    /// Controls how Activity is retried. If not set, the server will assign default retry policy.
944    #[builder(into)]
945    pub retry_policy: Option<RetryPolicy>,
946    /// Priority to use when starting this activity.
947    #[builder(default)]
948    pub priority: Priority,
949    /// Specifies behavior if there's a *closed* activity with the same ID.
950    #[builder(default)]
951    pub id_reuse_policy: ActivityIdReusePolicy,
952    /// Specifies behavior if there's a *running* activity with the same ID. Note that there can
953    /// only be one running activity for each Activity ID.
954    #[builder(default)]
955    pub id_conflict_policy: ActivityIdConflictPolicy,
956    /// Search attributes for the activity.
957    pub search_attributes: Option<SearchAttributes>,
958    /// Headers to include with the start request.
959    pub header: Option<Header>,
960    /// Single-line static summary for the activity, shown in the Temporal UI.
961    pub summary: Option<String>,
962    /// Multi-line static details for the activity, shown in the Temporal UI.
963    pub static_details: Option<String>,
964    /// Time to wait before dispatching the first activity task.
965    /// This delay is not applied to retry attempts.
966    pub start_delay: Option<Duration>,
967}
968
969impl ActivityStartOptions {
970    /// Returns a builder with `close_timeouts` set to [`ActivityCloseTimeouts::StartToClose`].
971    pub fn with_start_to_close_timeout(
972        task_queue: impl Into<String>,
973        activity_id: impl Into<String>,
974        start_to_close_timeout: Duration,
975    ) -> ActivityStartOptionsBuilder {
976        Self::new(
977            task_queue,
978            activity_id,
979            ActivityCloseTimeouts::StartToClose(start_to_close_timeout),
980        )
981    }
982
983    /// Returns a builder with `close_timeouts` set to [`ActivityCloseTimeouts::ScheduleToClose`].
984    pub fn with_schedule_to_close_timeout(
985        task_queue: impl Into<String>,
986        activity_id: impl Into<String>,
987        schedule_to_close_timeout: Duration,
988    ) -> ActivityStartOptionsBuilder {
989        Self::new(
990            task_queue,
991            activity_id,
992            ActivityCloseTimeouts::ScheduleToClose(schedule_to_close_timeout),
993        )
994    }
995}
996
997/// Specifies behavior when starting a standalone activity if there's a *closed* activity with
998/// the same ID. See [`ActivityStartOptions::id_reuse_policy`].
999#[non_exhaustive]
1000#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
1001pub enum ActivityIdReusePolicy {
1002    #[default]
1003    /// Always allow starting an activity using the same activity ID. This is the default.
1004    AllowDuplicate,
1005    /// Allow starting an activity using the same ID only when the last execution did not complete
1006    /// successfully.
1007    AllowDuplicateFailedOnly,
1008    /// Do not permit re-use of the ID for this activity.
1009    RejectDuplicate,
1010}
1011
1012impl From<ActivityIdReusePolicy> for ProtoActivityIdReusePolicy {
1013    fn from(value: ActivityIdReusePolicy) -> Self {
1014        match value {
1015            ActivityIdReusePolicy::AllowDuplicate => Self::AllowDuplicate,
1016            ActivityIdReusePolicy::AllowDuplicateFailedOnly => Self::AllowDuplicateFailedOnly,
1017            ActivityIdReusePolicy::RejectDuplicate => Self::RejectDuplicate,
1018        }
1019    }
1020}
1021
1022/// Specifies behavior when starting a standalone activity if there's a *running* activity with
1023/// the same ID. See [`ActivityStartOptions::id_conflict_policy`].
1024#[non_exhaustive]
1025#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
1026pub enum ActivityIdConflictPolicy {
1027    #[default]
1028    /// Don't start a new activity; instead return
1029    /// [`StartActivityError::AlreadyStarted`](crate::errors::StartActivityError::AlreadyStarted).
1030    Fail,
1031    /// Don't start a new activity; instead return a handle for the running activity.
1032    UseExisting,
1033}
1034
1035impl From<ActivityIdConflictPolicy> for ProtoActivityIdConflictPolicy {
1036    fn from(value: ActivityIdConflictPolicy) -> Self {
1037        match value {
1038            ActivityIdConflictPolicy::Fail => Self::Fail,
1039            ActivityIdConflictPolicy::UseExisting => Self::UseExisting,
1040        }
1041    }
1042}
1043
1044/// Options for listing activities.
1045#[derive(Debug, Clone, Default, bon::Builder)]
1046#[non_exhaustive]
1047pub struct ActivityListOptions {}
1048
1049/// Options for counting activities.
1050#[derive(Debug, Clone, Default, bon::Builder)]
1051#[non_exhaustive]
1052pub struct ActivityCountOptions {}
1053
1054/// Controls which optional fields will be requested in
1055/// [`ActivityHandle::describe`](crate::ActivityHandle::describe) operation. The fields will be
1056/// present in returned [`ActivityExecutionDescription`](crate::ActivityExecutionDescription),
1057/// subject to data availability and server support.
1058///
1059/// Note that these fields contain payloads that can be arbitrarily large. It's recommended not to
1060/// include them unless they're needed.
1061#[derive(Debug, Clone, Default, bon::Builder)]
1062#[non_exhaustive]
1063pub struct ActivityDescribeOptions {
1064    /// If set and the activity received input, the input will be included.
1065    #[builder(default)]
1066    pub include_input: bool,
1067    /// If set and the activity is closed, the activity outcome will be included.
1068    #[builder(default)]
1069    pub include_outcome: bool,
1070    /// If set and the activity sent heartbeat details, the heartbeat details will be included.
1071    #[builder(default)]
1072    pub include_heartbeat_details: bool,
1073    /// If set and the activity has a failed attempt, the last failure will be included.
1074    #[builder(default)]
1075    pub include_last_failure: bool,
1076}
1077
1078/// Options for [`ActivityHandle::cancel`](crate::ActivityHandle::cancel).
1079#[derive(Debug, Clone, Default, bon::Builder)]
1080#[builder(on(String, into))]
1081#[non_exhaustive]
1082pub struct ActivityCancelOptions {
1083    /// Reason for cancellation. Can be empty.
1084    #[builder(default)]
1085    pub reason: String,
1086}
1087
1088/// Options for [`ActivityHandle::terminate`](crate::ActivityHandle::terminate).
1089#[derive(Debug, Clone, Default, bon::Builder)]
1090#[builder(on(String, into))]
1091#[non_exhaustive]
1092pub struct ActivityTerminateOptions {
1093    /// Reason for termination. Can be empty.
1094    #[builder(default)]
1095    pub reason: String,
1096}