1use chrono::{DateTime, Utc};
2use serde::Serialize;
3use serde_json::Value;
4
5#[derive(Debug, Clone, Default, Serialize, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct RetryOptions {
9 #[serde(rename = "firstRetryIntervalInMilliseconds")]
11 pub first_retry_interval_ms: i32,
12
13 #[serde(rename = "maxNumberOfAttempts")]
15 pub max_attempts: i32,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub backoff_coefficient: Option<f64>,
20
21 #[serde(
23 rename = "maxRetryIntervalInMilliseconds",
24 skip_serializing_if = "Option::is_none"
25 )]
26 pub max_retry_interval_ms: Option<i32>,
27
28 #[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}