azure_functions/durable/
actions.rs

1use chrono::{DateTime, Utc};
2use serde::Serialize;
3use serde_json::Value;
4
5/// Defines retry policies that can be passed as parameters to various Durable Functions operations.
6#[derive(Debug, Clone, Default, Serialize, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct RetryOptions {
9    /// The first retry interval in milliseconds.
10    #[serde(rename = "firstRetryIntervalInMilliseconds")]
11    pub first_retry_interval_ms: i32,
12
13    /// The maximum number of retry attempts.
14    #[serde(rename = "maxNumberOfAttempts")]
15    pub max_attempts: i32,
16
17    /// The backoff coefficient used to determine rate of increase of backoff. Defaults to 1.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub backoff_coefficient: Option<f64>,
20
21    /// The max retry interval in milliseconds.
22    #[serde(
23        rename = "maxRetryIntervalInMilliseconds",
24        skip_serializing_if = "Option::is_none"
25    )]
26    pub max_retry_interval_ms: Option<i32>,
27
28    /// The timeout for retries in milliseconds.
29    #[serde(
30        rename = "retryTimeoutInMilliseconds",
31        skip_serializing_if = "Option::is_none"
32    )]
33    pub retry_timeout_ms: Option<i32>,
34}
35
36#[allow(dead_code)]
37#[derive(Debug, Clone, Serialize, PartialEq)]
38#[serde(tag = "actionType", rename_all = "camelCase")]
39pub(crate) enum Action {
40    #[serde(rename_all = "camelCase")]
41    CallActivity { function_name: String, input: Value },
42
43    #[serde(rename_all = "camelCase")]
44    CallActivityWithRetry {
45        function_name: String,
46        retry_options: RetryOptions,
47        input: Value,
48    },
49
50    #[serde(rename_all = "camelCase")]
51    CallSubOrchestrator {
52        function_name: String,
53        instance_id: Option<String>,
54        input: Value,
55    },
56
57    #[serde(rename_all = "camelCase")]
58    CallSubOrchestratorWithRetry {
59        function_name: String,
60        retry_options: RetryOptions,
61        instance_id: Option<String>,
62        input: Value,
63    },
64
65    #[serde(rename_all = "camelCase")]
66    ContinueAsNew {
67        input: Value,
68        preserve_unprocessed_events: bool,
69    },
70
71    #[serde(rename_all = "camelCase")]
72    CreateTimer {
73        fire_at: DateTime<Utc>,
74
75        #[serde(rename = "isCanceled")]
76        canceled: bool,
77    },
78
79    #[serde(rename_all = "camelCase")]
80    WaitForExternalEvent { external_event_name: String },
81}
82
83#[cfg(test)]
84mod tests {
85    use crate::durable::{Action, RetryOptions};
86    use chrono::{DateTime, Utc};
87
88    macro_rules! it_converts_to_json {
89        ($($name:ident: $value:expr,)*) => {
90            $(
91                #[test]
92                fn $name() {
93                    let (action, expected) = $value;
94                    let json = serde_json::to_string(&action).unwrap();
95                    assert_eq!(expected, json);
96                }
97            )*
98            }
99        }
100    it_converts_to_json! {
101        call_activity_converts_to_json:
102        (
103            Action::CallActivity {
104                function_name: "hello".to_owned(),
105                input: "World".into(),
106            },
107            r#"{"actionType":"callActivity","functionName":"hello","input":"World"}"#
108        ),
109        call_activity_with_retry_converts_to_json:
110        (
111            Action::CallActivityWithRetry {
112                function_name: "hello".to_owned(),
113                retry_options: RetryOptions {
114                    first_retry_interval_ms: 1000,
115                    max_attempts: 3,
116                    ..Default::default()
117                },
118                input: "World".into(),
119            },
120            r#"{"actionType":"callActivityWithRetry","functionName":"hello","retryOptions":{"firstRetryIntervalInMilliseconds":1000,"maxNumberOfAttempts":3},"input":"World"}"#
121        ),
122        call_sub_orchestrator_converts_to_json:
123        (
124            Action::CallSubOrchestrator {
125                function_name: "hello".to_string(),
126                instance_id: Some("1231232144".to_string()),
127                input: "World".into()
128            },
129            r#"{"actionType":"callSubOrchestrator","functionName":"hello","instanceId":"1231232144","input":"World"}"#
130        ),
131        call_sub_orchestrator_with_retry_converts_to_json:
132        (
133            Action::CallSubOrchestratorWithRetry {
134                function_name: "hello".to_string(),
135                retry_options: RetryOptions {
136                    first_retry_interval_ms: 1000,
137                    max_attempts: 3,
138                    ..Default::default()
139                },
140                instance_id: Some("1231232144".to_string()),
141                input: "World".into()
142            },
143            r#"{"actionType":"callSubOrchestratorWithRetry","functionName":"hello","retryOptions":{"firstRetryIntervalInMilliseconds":1000,"maxNumberOfAttempts":3},"instanceId":"1231232144","input":"World"}"#
144        ),
145        continue_as_new_converts_to_json:
146        (
147            Action::ContinueAsNew { input: "World".into(), preserve_unprocessed_events: true, },
148            r#"{"actionType":"continueAsNew","input":"World","preserveUnprocessedEvents":true}"#
149        ),
150        create_timer_converts_to_json:
151        (
152           Action::CreateTimer {
153                fire_at: DateTime::<Utc>::from(DateTime::parse_from_rfc3339("2019-07-18T06:22:27.016757Z").unwrap()),
154                canceled: true,
155           },
156           r#"{"actionType":"createTimer","fireAt":"2019-07-18T06:22:27.016757Z","isCanceled":true}"#
157        ),
158        wait_for_external_event_converts_to_json:
159        (
160            Action::WaitForExternalEvent { external_event_name: "SmsChallengeResponse".to_string() },
161            r#"{"actionType":"waitForExternalEvent","externalEventName":"SmsChallengeResponse"}"#
162        ),
163    }
164}