Skip to main content

dapr_durabletask/task/
options.rs

1use crate::api::{HistoryPropagationScope, RetryPolicy};
2
3/// Options for scheduling an activity call from an orchestrator.
4#[derive(Default, Clone)]
5pub struct ActivityOptions {
6    /// Route the activity to a specific Dapr app ID (cross-app invocation).
7    pub app_id: Option<String>,
8    /// Retry policy to apply when the activity fails.
9    pub retry_policy: Option<RetryPolicy>,
10    /// Forward the calling workflow's history to the activity. See
11    /// [`HistoryPropagationScope`] for the trade-off between
12    /// `OwnHistory` (caller only) and `Lineage` (caller + ancestors).
13    pub history_propagation_scope: Option<HistoryPropagationScope>,
14}
15
16impl ActivityOptions {
17    /// Create an `ActivityOptions` with all fields unset.
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    /// Route the activity to a specific Dapr app ID (cross-app invocation).
23    pub fn with_app_id(mut self, app_id: impl Into<String>) -> Self {
24        self.app_id = Some(app_id.into());
25        self
26    }
27
28    /// Attach a retry policy applied when the activity fails.
29    pub fn with_retry_policy(mut self, policy: RetryPolicy) -> Self {
30        self.retry_policy = Some(policy);
31        self
32    }
33
34    /// Forward the calling workflow's history to the activity under the given
35    /// scope.
36    pub fn with_history_propagation(mut self, scope: HistoryPropagationScope) -> Self {
37        self.history_propagation_scope = Some(scope);
38        self
39    }
40}
41
42/// Options for scheduling a sub-orchestration call from an orchestrator.
43#[derive(Default, Clone)]
44pub struct SubOrchestratorOptions {
45    /// Explicit instance ID for the sub-orchestration.
46    /// If `None`, a random UUID is generated for each attempt.
47    pub instance_id: Option<String>,
48    /// Route the sub-orchestration to a specific Dapr app ID.
49    pub app_id: Option<String>,
50    /// Retry policy to apply when the sub-orchestration fails.
51    pub retry_policy: Option<RetryPolicy>,
52    /// Forward the calling workflow's history to the child workflow.
53    pub history_propagation_scope: Option<HistoryPropagationScope>,
54}
55
56impl SubOrchestratorOptions {
57    /// Create a `SubOrchestratorOptions` with all fields unset.
58    pub fn new() -> Self {
59        Self::default()
60    }
61
62    /// Use the given explicit instance ID for the sub-orchestration.
63    /// If unset, a random UUID is generated for each attempt.
64    pub fn with_instance_id(mut self, id: impl Into<String>) -> Self {
65        self.instance_id = Some(id.into());
66        self
67    }
68
69    /// Route the sub-orchestration to a specific Dapr app ID.
70    pub fn with_app_id(mut self, app_id: impl Into<String>) -> Self {
71        self.app_id = Some(app_id.into());
72        self
73    }
74
75    /// Attach a retry policy applied when the sub-orchestration fails.
76    pub fn with_retry_policy(mut self, policy: RetryPolicy) -> Self {
77        self.retry_policy = Some(policy);
78        self
79    }
80
81    /// Forward the calling workflow's history to the child workflow under the
82    /// given scope.
83    pub fn with_history_propagation(mut self, scope: HistoryPropagationScope) -> Self {
84        self.history_propagation_scope = Some(scope);
85        self
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use std::time::Duration;
93
94    fn test_retry_policy() -> RetryPolicy {
95        RetryPolicy::new(3, Duration::from_secs(1))
96    }
97
98    #[test]
99    fn activity_options_defaults() {
100        let opts = ActivityOptions::new();
101        assert!(opts.app_id.is_none());
102        assert!(opts.retry_policy.is_none());
103    }
104
105    #[test]
106    fn activity_options_with_app_id() {
107        let opts = ActivityOptions::new().with_app_id("my-app");
108        assert_eq!(opts.app_id.as_deref(), Some("my-app"));
109    }
110
111    #[test]
112    fn activity_options_with_retry_policy() {
113        let opts = ActivityOptions::new().with_retry_policy(test_retry_policy());
114        assert!(opts.retry_policy.is_some());
115    }
116
117    #[test]
118    fn activity_options_builder_chaining() {
119        let opts = ActivityOptions::new()
120            .with_app_id("chained")
121            .with_retry_policy(test_retry_policy());
122        assert_eq!(opts.app_id.as_deref(), Some("chained"));
123        assert!(opts.retry_policy.is_some());
124    }
125
126    #[test]
127    fn sub_orchestrator_options_defaults() {
128        let opts = SubOrchestratorOptions::new();
129        assert!(opts.instance_id.is_none());
130        assert!(opts.app_id.is_none());
131        assert!(opts.retry_policy.is_none());
132    }
133
134    #[test]
135    fn sub_orchestrator_options_with_instance_id() {
136        let opts = SubOrchestratorOptions::new().with_instance_id("inst-1");
137        assert_eq!(opts.instance_id.as_deref(), Some("inst-1"));
138    }
139
140    #[test]
141    fn sub_orchestrator_options_with_app_id() {
142        let opts = SubOrchestratorOptions::new().with_app_id("sub-app");
143        assert_eq!(opts.app_id.as_deref(), Some("sub-app"));
144    }
145
146    #[test]
147    fn sub_orchestrator_options_with_retry_policy() {
148        let opts = SubOrchestratorOptions::new().with_retry_policy(test_retry_policy());
149        assert!(opts.retry_policy.is_some());
150    }
151
152    #[test]
153    fn sub_orchestrator_options_builder_chaining() {
154        let opts = SubOrchestratorOptions::new()
155            .with_instance_id("inst-2")
156            .with_app_id("sub-app-2")
157            .with_retry_policy(test_retry_policy());
158        assert_eq!(opts.instance_id.as_deref(), Some("inst-2"));
159        assert_eq!(opts.app_id.as_deref(), Some("sub-app-2"));
160        assert!(opts.retry_policy.is_some());
161    }
162}