1pub mod error;
2pub mod fmt;
3mod headers;
4#[cfg(feature = "request_identity")]
5mod request_identity;
6mod retries;
7mod service_protocol;
8#[cfg(feature = "tracing_pretty")]
9pub mod tracing_pretty;
10mod vm;
11
12use bytes::Bytes;
13use std::borrow::Cow;
14use std::time::Duration;
15
16pub use crate::retries::{OnMaxAttempts, RetryPolicy};
17pub use error::Error;
18pub use headers::HeaderMap;
19#[cfg(feature = "request_identity")]
20pub use request_identity::*;
21pub use service_protocol::Version;
22pub use vm::CoreVM;
23
24#[derive(Debug, Clone, Copy, Default)]
26#[non_exhaustive]
27pub struct PayloadOptions {
28 pub unstable_serialization: bool,
31}
32
33impl PayloadOptions {
34 pub fn stable_serialization() -> Self {
36 Self {
37 unstable_serialization: false,
38 }
39 }
40
41 pub fn unstable_serialization() -> Self {
44 Self {
45 unstable_serialization: true,
46 }
47 }
48}
49
50#[derive(Debug, Eq, PartialEq)]
51pub struct Header {
52 pub key: Cow<'static, str>,
53 pub value: Cow<'static, str>,
54}
55
56#[derive(Debug)]
57#[non_exhaustive]
58pub struct ResponseHead {
59 pub status_code: u16,
60 pub headers: Vec<Header>,
61 pub version: Version,
62}
63
64#[derive(Debug, Eq, PartialEq)]
65#[non_exhaustive]
66pub struct Input {
67 pub invocation_id: String,
68 pub random_seed: u64,
69 pub key: String,
70 pub headers: Vec<Header>,
71 pub input: Bytes,
72 pub scope: Option<String>,
74 pub limit_key: Option<String>,
76 pub idempotency_key: Option<String>,
78}
79
80#[derive(Debug, Copy, Clone, Eq, PartialEq)]
81#[non_exhaustive]
82pub enum CommandType {
83 Input,
84 Output,
85 GetState,
86 GetStateKeys,
87 SetState,
88 ClearState,
89 ClearAllState,
90 GetPromise,
91 PeekPromise,
92 CompletePromise,
93 Sleep,
94 Call,
95 OneWayCall,
96 SendSignal,
97 Run,
98 AttachInvocation,
99 GetInvocationOutput,
100 CompleteAwakeable,
101 CancelInvocation,
102}
103
104impl std::fmt::Display for CommandType {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 f.write_str(match self {
107 CommandType::Input => "handler input",
108 CommandType::Output => "handler return",
109 CommandType::GetState => "get state",
110 CommandType::GetStateKeys => "get state keys",
111 CommandType::SetState => "set state",
112 CommandType::ClearState => "clear state",
113 CommandType::ClearAllState => "clear all state",
114 CommandType::GetPromise => "get promise",
115 CommandType::PeekPromise => "peek promise",
116 CommandType::CompletePromise => "complete promise",
117 CommandType::Sleep => "sleep",
118 CommandType::Call => "call",
119 CommandType::OneWayCall => "one way call/send",
120 CommandType::SendSignal => "send signal",
121 CommandType::Run => "run",
122 CommandType::AttachInvocation => "attach invocation",
123 CommandType::GetInvocationOutput => "get invocation output",
124 CommandType::CompleteAwakeable => "complete awakeable",
125 CommandType::CancelInvocation => "cancel invocation",
126 })
127 }
128}
129
130#[derive(Debug, Clone, Eq, PartialEq)]
132pub enum CommandRelationship {
133 Last,
134 Next {
135 ty: CommandType,
136 name: Option<Cow<'static, str>>,
137 },
138 Specific {
139 command_index: u32,
140 ty: CommandType,
141 name: Option<Cow<'static, str>>,
142 },
143}
144
145#[derive(Debug, Eq, PartialEq)]
146pub struct Target {
147 pub service: String,
148 pub handler: String,
149 pub key: Option<String>,
150 pub idempotency_key: Option<String>,
151 pub scope: Option<String>,
153 pub limit_key: Option<String>,
155 pub headers: Vec<Header>,
156}
157
158pub const CANCEL_NOTIFICATION_HANDLE: NotificationHandle = NotificationHandle(1);
159
160#[derive(Debug, Hash, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
161pub struct NotificationHandle(u32);
162
163impl From<u32> for NotificationHandle {
164 fn from(value: u32) -> Self {
165 NotificationHandle(value)
166 }
167}
168
169impl From<NotificationHandle> for u32 {
170 fn from(value: NotificationHandle) -> Self {
171 value.0
172 }
173}
174
175#[derive(Debug, Clone, Copy, Eq, PartialEq)]
176pub struct CallHandle {
177 pub invocation_id_notification_handle: NotificationHandle,
178 pub call_notification_handle: NotificationHandle,
179}
180
181#[derive(Debug, Clone, Copy, Eq, PartialEq)]
182pub struct SendHandle {
183 pub invocation_id_notification_handle: NotificationHandle,
184}
185
186#[derive(Debug, Eq, PartialEq, Clone, strum::IntoStaticStr)]
187pub enum Value {
188 Void,
190 Success(Bytes),
191 Failure(TerminalFailure),
192 StateKeys(Vec<String>),
194 InvocationId(String),
196}
197
198#[derive(Debug, Clone, Eq, PartialEq)]
200pub struct TerminalFailure {
201 pub code: u16,
202 pub message: String,
203 pub metadata: Vec<(String, String)>,
204}
205
206#[derive(Debug, Default)]
207pub struct EntryRetryInfo {
208 pub retry_count: u32,
210 pub retry_loop_duration: Duration,
212}
213
214#[derive(Debug, Clone)]
215pub enum RunExitResult {
216 Success(Bytes),
217 TerminalFailure(TerminalFailure),
218 RetryableFailure {
219 attempt_duration: Duration,
220 error: Error,
221 },
222}
223
224#[derive(Debug, Clone)]
225pub enum NonEmptyValue {
226 Success(Bytes),
227 Failure(TerminalFailure),
228}
229
230impl From<NonEmptyValue> for Value {
231 fn from(value: NonEmptyValue) -> Self {
232 match value {
233 NonEmptyValue::Success(s) => Value::Success(s),
234 NonEmptyValue::Failure(f) => Value::Failure(f),
235 }
236 }
237}
238
239#[derive(Debug, Eq, PartialEq)]
240pub enum AttachInvocationTarget {
241 InvocationId(String),
242 WorkflowId {
243 name: String,
244 key: String,
245 scope: Option<String>,
247 },
248 IdempotencyId {
249 service_name: String,
250 service_key: Option<String>,
251 handler_name: String,
252 idempotency_key: String,
253 scope: Option<String>,
255 },
256}
257
258pub type VMResult<T> = Result<T, Error>;
259
260#[derive(Debug, Copy, Clone, Default)]
261pub enum AwaitingOnPolicy {
262 SendAlways,
263 #[default]
264 DontSendWhenExecutingRun,
265 DontSend,
266}
267
268#[derive(Debug)]
269pub enum ImplicitCancellationOption {
270 Disabled,
271 Enabled {
272 cancel_children_calls: bool,
273 cancel_children_one_way_calls: bool,
274 },
275}
276
277#[derive(Debug, Default)]
278pub enum NonDeterministicChecksOption {
279 PayloadChecksDisabled,
282 #[default]
283 Enabled,
284}
285
286#[derive(Debug, Default)]
289pub enum JournalMismatchRetryBehavior {
290 Pause,
295 FailTerminally,
300 #[default]
302 FollowRetryPolicy,
303}
304
305#[derive(Debug)]
306pub struct VMOptions {
307 pub implicit_cancellation: ImplicitCancellationOption,
308 pub non_determinism_checks: NonDeterministicChecksOption,
309 pub awaiting_on_policy: AwaitingOnPolicy,
310 pub journal_mismatch_retry_behavior: JournalMismatchRetryBehavior,
311}
312
313impl Default for VMOptions {
314 fn default() -> Self {
315 Self {
316 implicit_cancellation: ImplicitCancellationOption::Enabled {
317 cancel_children_calls: true,
318 cancel_children_one_way_calls: false,
319 },
320 non_determinism_checks: Default::default(),
321 awaiting_on_policy: Default::default(),
322 journal_mismatch_retry_behavior: Default::default(),
323 }
324 }
325}
326
327#[derive(Clone)]
328#[cfg_attr(test, derive(Eq, PartialEq))]
329#[non_exhaustive]
330pub enum UnresolvedFuture {
331 Single(NotificationHandle),
333 FirstCompleted(Vec<UnresolvedFuture>),
335 AllCompleted(Vec<UnresolvedFuture>),
337 FirstSucceededOrAllFailed(Vec<UnresolvedFuture>),
339 AllSucceededOrFirstFailed(Vec<UnresolvedFuture>),
341 Unknown(Vec<UnresolvedFuture>),
344}
345
346impl From<NotificationHandle> for UnresolvedFuture {
347 fn from(value: NotificationHandle) -> Self {
348 Self::Single(value)
349 }
350}
351
352impl std::fmt::Debug for UnresolvedFuture {
353 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
354 fn fmt_combinator(
355 f: &mut std::fmt::Formatter<'_>,
356 name: &str,
357 children: &[UnresolvedFuture],
358 ) -> std::fmt::Result {
359 write!(f, "{name}(")?;
360 for (i, child) in children.iter().enumerate() {
361 if i > 0 {
362 write!(f, ", ")?;
363 }
364 write!(f, "{child:?}")?;
365 }
366 write!(f, ")")
367 }
368
369 match self {
370 UnresolvedFuture::Unknown(children) => fmt_combinator(f, "unknown", children),
371 UnresolvedFuture::Single(h) => write!(f, "{}", u32::from(*h)),
372 UnresolvedFuture::FirstCompleted(children) => {
373 fmt_combinator(f, "first_completed", children)
374 }
375 UnresolvedFuture::AllCompleted(children) => {
376 fmt_combinator(f, "all_completed", children)
377 }
378 UnresolvedFuture::FirstSucceededOrAllFailed(children) => {
379 fmt_combinator(f, "first_succeeded_or_all_failed", children)
380 }
381 UnresolvedFuture::AllSucceededOrFirstFailed(children) => {
382 fmt_combinator(f, "all_succeeded_or_first_failed", children)
383 }
384 }
385 }
386}
387
388#[derive(Debug, PartialEq, Eq)]
389pub enum AwaitResponse {
390 AnyCompleted,
394 WaitingExternalProgress {
397 waiting_input: bool,
399 waiting_run_proposal: bool,
401 },
402 ExecuteRun(NotificationHandle),
404 CancelSignalReceived,
406}
407
408#[derive(Debug, Copy, Clone, Eq, PartialEq, strum::EnumIs)]
409#[repr(u8)]
410pub enum State {
411 WaitingPreFlight = 0,
412 Replaying = 1,
413 Processing = 2,
414 Closed = 3,
415}
416
417#[derive(Debug, Clone, Eq, PartialEq)]
418pub struct AwakeableHandle {
419 pub id: String,
420 pub handle: NotificationHandle,
421}
422
423#[derive(Debug, Clone, Eq, PartialEq)]
424pub struct RunHandle {
425 pub replayed: bool,
427 pub handle: NotificationHandle,
428}
429
430pub trait VM: Sized {
431 fn new(request_headers: impl HeaderMap, options: VMOptions) -> VMResult<Self>;
432
433 fn get_response_head(&self) -> ResponseHead;
434
435 fn notify_input(&mut self, buffer: Bytes);
438
439 fn notify_input_closed(&mut self);
440
441 fn notify_error(&mut self, error: Error, related_command: Option<CommandRelationship>);
444
445 fn take_output(&mut self) -> Bytes;
449
450 fn is_ready_to_execute(&self) -> VMResult<bool>;
453
454 fn is_completed(&self, handle: NotificationHandle) -> bool;
457
458 fn do_await(&mut self, unresolved_future: UnresolvedFuture) -> VMResult<AwaitResponse>;
459
460 fn take_notification(&mut self, handle: NotificationHandle) -> VMResult<Option<Value>>;
461
462 fn sys_input(&mut self) -> VMResult<Input>;
465
466 fn sys_state_get(
467 &mut self,
468 key: String,
469 options: PayloadOptions,
470 ) -> VMResult<NotificationHandle>;
471
472 fn sys_state_get_keys(&mut self) -> VMResult<NotificationHandle>;
473
474 fn sys_state_set(&mut self, key: String, value: Bytes, options: PayloadOptions)
475 -> VMResult<()>;
476
477 fn sys_state_clear(&mut self, key: String) -> VMResult<()>;
478
479 fn sys_state_clear_all(&mut self) -> VMResult<()>;
480
481 fn sys_sleep(
483 &mut self,
484 name: String,
485 wake_up_time_since_unix_epoch: Duration,
486 now_since_unix_epoch: Option<Duration>,
487 ) -> VMResult<NotificationHandle>;
488
489 fn sys_call(
490 &mut self,
491 target: Target,
492 input: Bytes,
493 name: Option<String>,
494 options: PayloadOptions,
495 ) -> VMResult<CallHandle>;
496
497 fn sys_send(
498 &mut self,
499 target: Target,
500 input: Bytes,
501 execution_time_since_unix_epoch: Option<Duration>,
502 name: Option<String>,
503 options: PayloadOptions,
504 ) -> VMResult<SendHandle>;
505
506 fn sys_awakeable(&mut self) -> VMResult<AwakeableHandle>;
507
508 fn sys_complete_awakeable(
509 &mut self,
510 id: String,
511 value: NonEmptyValue,
512 options: PayloadOptions,
513 ) -> VMResult<()>;
514
515 fn create_signal_handle(&mut self, signal_name: String) -> VMResult<NotificationHandle>;
516
517 fn sys_complete_signal(
518 &mut self,
519 target_invocation_id: String,
520 signal_name: String,
521 value: NonEmptyValue,
522 ) -> VMResult<()>;
523
524 fn sys_get_promise(&mut self, key: String) -> VMResult<NotificationHandle>;
525
526 fn sys_peek_promise(&mut self, key: String) -> VMResult<NotificationHandle>;
527
528 fn sys_complete_promise(
529 &mut self,
530 key: String,
531 value: NonEmptyValue,
532 options: PayloadOptions,
533 ) -> VMResult<NotificationHandle>;
534
535 fn sys_run(&mut self, name: String) -> VMResult<RunHandle>;
536
537 fn propose_run_completion(
538 &mut self,
539 notification_handle: NotificationHandle,
540 value: RunExitResult,
541 retry_policy: RetryPolicy,
542 ) -> VMResult<()>;
543
544 fn sys_cancel_invocation(&mut self, target_invocation_id: String) -> VMResult<()>;
545
546 fn sys_attach_invocation(
547 &mut self,
548 target: AttachInvocationTarget,
549 ) -> VMResult<NotificationHandle>;
550
551 fn sys_get_invocation_output(
552 &mut self,
553 target: AttachInvocationTarget,
554 ) -> VMResult<NotificationHandle>;
555
556 fn sys_write_output(&mut self, value: NonEmptyValue, options: PayloadOptions) -> VMResult<()>;
557
558 fn sys_end(&mut self) -> VMResult<()>;
559
560 fn state(&self) -> State;
562
563 fn last_command_index(&self) -> i64;
565}
566
567#[cfg(test)]
568mod tests;