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