Skip to main content

dex_sdk/
flow_config.rs

1// Copyright (c) 2026 Super Durable, Inc.
2//
3// Licensed under the Sustainable Use License 1.0.
4// You may not use this file except in compliance with the License.
5// See the LICENSE file in the repository root.
6//
7// SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
9use crate::StepDurability;
10
11#[derive(Clone, Debug, Default)]
12/// Overrides runtime behavior for one Flow.
13///
14/// StartFlow and SubFlow always select pull Workers, even when no override is supplied.
15/// [`crate::Client::update_flow_config`] leaves the Worker target unset, preserving the active Flow
16/// target. Other omitted fields use server defaults for StartFlow, inherit the parent configuration
17/// for SubFlow, and retain the active Flow setting for updates.
18/// Pass a value to [`crate::StartFlowOptions::config_override`] for one execution or to
19/// [`crate::Client::update_flow_config`] for an active Flow.
20pub struct FlowConfig {
21    pub(crate) active_step_search_mode: Option<ActiveStepSearchMode>,
22    pub(crate) attribute_store_names: Option<Vec<String>>,
23    pub(crate) step_durability: Option<StepDurability>,
24    pub(crate) history_window_events: Option<u32>,
25    pub(crate) offload_history: Option<bool>,
26}
27
28impl FlowConfig {
29    /// Creates a config with no overrides.
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    /// Controls which active Step types Dex places in the search index.
35    pub fn active_step_search_mode(mut self, value: ActiveStepSearchMode) -> Self {
36        self.active_step_search_mode = Some(value);
37        self
38    }
39
40    /// Selects server-configured Attribute Stores for opted-in Attribute writes.
41    ///
42    /// Omitting this builder preserves the existing Flow setting. Passing an empty vector retains
43    /// protocol presence and disables later synchronization. Each enabled Attribute write is
44    /// projected to every selected store; an external store failure does not roll back the Flow
45    /// Attribute write.
46    #[must_use]
47    pub fn attribute_store_names(mut self, values: Vec<String>) -> Self {
48        self.attribute_store_names = Some(values);
49        self
50    }
51
52    /// Sets the default persistence durability for Step handler writes.
53    pub fn step_durability(mut self, value: StepDurability) -> Self {
54        self.step_durability = Some(value);
55        self
56    }
57
58    /// Has no effect. The SDK does not send this value to the server.
59    ///
60    /// server-zd 0.1.23 and later ignore the field for runs that start with them. Such a run,
61    /// when it offloads its history, always deletes the objects of expired history segments about
62    /// one hour after the history window passes them.
63    ///
64    /// A run that started under server-zd 0.1.22 still follows the value it recorded then. When
65    /// that value is false, the run's expired history objects stay in object storage until its
66    /// retention ends, and a run that never closes keeps them. To delete them sooner, set the
67    /// field to true for that run with UpdateFlowConfig through an SDK older than 1.40.0 or a
68    /// direct gRPC request. See <https://docs.superdurable.io/reference/server/configuration#history-offload>.
69    ///
70    /// The method remains so existing code still compiles. Returns this config unchanged.
71    ///
72    /// Since 1.39.0.
73    ///
74    /// Deprecated in 1.40.0: the SDK no longer sends the value, and runs that start with
75    /// server-zd 0.1.23 or later ignore it. Remove the call.
76    #[deprecated(
77        since = "1.40.0",
78        note = "has no effect; the SDK no longer sends it, and runs started on server-zd 0.1.23 \
79                or later ignore it"
80    )]
81    #[must_use]
82    pub fn delete_expired_history_objects(self, _value: bool) -> Self {
83        self
84    }
85
86    /// Sets how many of the newest history events the run keeps, approximately.
87    ///
88    /// The run uses the kept events for history reads and Time Travel. Without this builder, the
89    /// run uses the server's `history.windowEvents` setting, which defaults to 10000. Raise it for
90    /// a run that you inspect or travel back in often. Lower it for a run that writes many events
91    /// and needs less disk.
92    ///
93    /// Dex prunes the oldest events in chunks, and only between commands, so a run keeps slightly
94    /// more or fewer events than the value. A command that changes the Flow but records no event
95    /// counts as one event. The first event of the run is always kept, so a reset to the beginning
96    /// of the run always works. History reads no longer return pruned events, and Time Travel
97    /// targets only commands inside the window.
98    ///
99    /// Set it at start through [`crate::StartFlowOptions::config_override`], or change it on an
100    /// active Flow with [`crate::Client::update_flow_config`]. A smaller value takes effect at the
101    /// run's next pruning. A larger value keeps more of the events recorded afterwards; pruned
102    /// events never come back. Once set, the value can be changed but not cleared back to the
103    /// server default: an update without this builder keeps the current value. A SubFlow inherits
104    /// the value from its parent unless its own [`crate::SubFlowOptions::config_override`] sets it.
105    ///
106    /// The value must be positive and at most the server's `history.maxWindowEvents` setting,
107    /// which defaults to 100000. StartFlow and UpdateFlowConfig return [`crate::SdkError::Service`]
108    /// whose [`crate::ServiceError::code`] is `InvalidArgument` for zero or a value above that
109    /// maximum. A value above `i32::MAX` fails locally with [`crate::SdkError::InvalidArgument`]
110    /// before any request. A Step that starts a SubFlow with an invalid override is an invalid Worker
111    /// response: the Step attempt fails and Dex retries it under the Step's retry policy. Servers
112    /// older than server-zd 0.1.21 ignore the value.
113    ///
114    /// ```no_run
115    /// # fn update(client: &dex_sdk::Client) -> dex_sdk::SdkResult<()> {
116    /// client.update_flow_config(
117    ///     "order-42",
118    ///     dex_sdk::FlowConfig::new().history_window_events(50_000),
119    /// )?;
120    /// # Ok(())
121    /// # }
122    /// ```
123    ///
124    /// Since 1.38.0.
125    #[must_use]
126    pub fn history_window_events(mut self, value: u32) -> Self {
127        self.history_window_events = Some(value);
128        self
129    }
130
131    /// Sets whether Dex offloads the run's history to object storage.
132    ///
133    /// Without this builder, the run offloads its history, as if `true` were passed. Leave it unset
134    /// for most runs.
135    ///
136    /// An offloaded run uploads its history to object storage in segment objects. Once a segment
137    /// is uploaded and a grace period has passed, Dex deletes its history records and superseded
138    /// values from the local disk. History reads then fetch them from object storage. When the
139    /// history window passes a whole segment, Dex deletes the segment's object about one hour
140    /// later.
141    ///
142    /// A run that does not offload keeps its history on the local disk. It never writes a history
143    /// object. The history window still applies: Dex prunes the oldest events and deletes the
144    /// superseded values that the window passed.
145    ///
146    /// A long-running run that offloads keeps only its newest history and current state on the
147    /// local disk. Pass `false` for many short runs that close soon after they start. Each
148    /// offloaded run writes at least one history object when it closes. It deletes that object
149    /// when its retention ends. Short runs at a high rate therefore add object storage requests,
150    /// while their small history costs little local disk. A run that does not offload keeps
151    /// every superseded value its history window covers on the local disk, with no byte limit;
152    /// for a run that rewrites large values, keep offload or set a smaller history window.
153    ///
154    /// Set it only at start, through [`crate::StartFlowOptions::config_override`], or for a
155    /// SubFlow through [`crate::SubFlowOptions::config_override`]. A SubFlow inherits the value
156    /// from its parent unless its own override sets it. The run keeps the value for its whole
157    /// life. [`crate::Client::update_flow_config`] with this builder returns
158    /// [`crate::SdkError::Service`] whose [`crate::ServiceError::code`] is `InvalidArgument`. Runs
159    /// that started before server-zd 0.1.23 keep the history offload behavior that their server
160    /// gave them. Servers older than server-zd 0.1.23 ignore the value.
161    ///
162    /// ```no_run
163    /// # fn start<F: dex_sdk::Flow>(
164    /// #     client: &dex_sdk::Client,
165    /// #     notification_flow: &F,
166    /// #     input: F::StartInput,
167    /// # ) -> dex_sdk::SdkResult<String> {
168    /// client.start_flow_with_options(
169    ///     notification_flow,
170    ///     "notification-42",
171    ///     input,
172    ///     dex_sdk::StartFlowOptions::new()
173    ///         .config_override(dex_sdk::FlowConfig::new().offload_history(false)),
174    /// )
175    /// # }
176    /// ```
177    ///
178    /// Since 1.40.0.
179    #[must_use]
180    pub fn offload_history(mut self, value: bool) -> Self {
181        self.offload_history = Some(value);
182        self
183    }
184}
185
186#[derive(Clone, Copy, Debug, Eq, PartialEq)]
187/// Controls which active Step types Dex indexes for Flow search.
188pub enum ActiveStepSearchMode {
189    /// Indexes every active Step type, including execute-only Steps.
190    All,
191    /// Indexes a Step type only after its `wait_for` handler runs.
192    WithWaitFor,
193    /// Disables active-Step indexing for the Flow.
194    Disabled,
195}