Skip to main content

restate_sdk/context/
mod.rs

1//! Types exposing Restate functionalities to service handlers.
2
3use crate::endpoint::{ContextInternal, InputMetadata};
4use crate::errors::{HandlerResult, TerminalError};
5use crate::serde::{Deserialize, Serialize};
6use std::future::Future;
7use std::time::Duration;
8
9#[doc(hidden)]
10pub mod macro_support;
11mod map;
12mod request;
13mod run;
14mod select;
15mod select_any;
16
17pub use map::{MapDurableFuture, MapErrDurableFuture, MapOkDurableFuture};
18pub use request::{CallFuture, InvocationHandle, Request, RequestTarget, SendHandle, SignalHandle};
19pub use run::{RunClosure, RunFuture, RunRetryPolicy};
20pub use select_any::DurableFuturesUnordered;
21
22pub type HeaderMap = http::HeaderMap<String>;
23
24/// Service handler context.
25pub struct Context<'ctx> {
26    invocation_id: String,
27    random_seed: u64,
28    #[cfg(feature = "rand")]
29    std_rng: rand::prelude::StdRng,
30    headers: HeaderMap,
31    scope: Option<String>,
32    limit_key: Option<String>,
33    idempotency_key: Option<String>,
34    inner: &'ctx ContextInternal,
35}
36
37impl Context<'_> {
38    /// Get invocation id.
39    pub fn invocation_id(&self) -> &str {
40        &self.invocation_id
41    }
42
43    /// Get request headers.
44    pub fn headers(&self) -> &HeaderMap {
45        &self.headers
46    }
47
48    /// Get request headers.
49    pub fn headers_mut(&mut self) -> &HeaderMap {
50        &mut self.headers
51    }
52
53    /// Scope this invocation was submitted with, if any.
54    pub fn scope(&self) -> Option<&str> {
55        self.scope.as_deref()
56    }
57
58    /// Limit key this invocation was submitted with, if any.
59    pub fn limit_key(&self) -> Option<&str> {
60        self.limit_key.as_deref()
61    }
62
63    /// Idempotency key this invocation was submitted with, if any.
64    pub fn idempotency_key(&self) -> Option<&str> {
65        self.idempotency_key.as_deref()
66    }
67}
68
69impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for Context<'ctx> {
70    fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
71        Self {
72            invocation_id: value.1.invocation_id,
73            random_seed: value.1.random_seed,
74            #[cfg(feature = "rand")]
75            std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
76            headers: value.1.headers,
77            scope: value.1.scope,
78            limit_key: value.1.limit_key,
79            idempotency_key: value.1.idempotency_key,
80            inner: value.0,
81        }
82    }
83}
84
85/// Object shared handler context.
86pub struct SharedObjectContext<'ctx> {
87    invocation_id: String,
88    key: String,
89    random_seed: u64,
90    #[cfg(feature = "rand")]
91    std_rng: rand::prelude::StdRng,
92    headers: HeaderMap,
93    scope: Option<String>,
94    limit_key: Option<String>,
95    idempotency_key: Option<String>,
96    pub(crate) inner: &'ctx ContextInternal,
97}
98
99impl SharedObjectContext<'_> {
100    /// Get invocation id.
101    pub fn invocation_id(&self) -> &str {
102        &self.invocation_id
103    }
104
105    /// Get object key.
106    pub fn key(&self) -> &str {
107        &self.key
108    }
109
110    /// Get request headers.
111    pub fn headers(&self) -> &HeaderMap {
112        &self.headers
113    }
114
115    /// Get request headers.
116    pub fn headers_mut(&mut self) -> &HeaderMap {
117        &mut self.headers
118    }
119
120    /// Scope this invocation was submitted with, if any.
121    pub fn scope(&self) -> Option<&str> {
122        self.scope.as_deref()
123    }
124
125    /// Limit key this invocation was submitted with, if any.
126    pub fn limit_key(&self) -> Option<&str> {
127        self.limit_key.as_deref()
128    }
129
130    /// Idempotency key this invocation was submitted with, if any.
131    pub fn idempotency_key(&self) -> Option<&str> {
132        self.idempotency_key.as_deref()
133    }
134}
135
136impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for SharedObjectContext<'ctx> {
137    fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
138        Self {
139            invocation_id: value.1.invocation_id,
140            key: value.1.key,
141            random_seed: value.1.random_seed,
142            #[cfg(feature = "rand")]
143            std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
144            headers: value.1.headers,
145            scope: value.1.scope,
146            limit_key: value.1.limit_key,
147            idempotency_key: value.1.idempotency_key,
148            inner: value.0,
149        }
150    }
151}
152
153/// Object handler context.
154pub struct ObjectContext<'ctx> {
155    invocation_id: String,
156    key: String,
157    random_seed: u64,
158    #[cfg(feature = "rand")]
159    std_rng: rand::prelude::StdRng,
160    headers: HeaderMap,
161    scope: Option<String>,
162    limit_key: Option<String>,
163    idempotency_key: Option<String>,
164    pub(crate) inner: &'ctx ContextInternal,
165}
166
167impl ObjectContext<'_> {
168    /// Get invocation id.
169    pub fn invocation_id(&self) -> &str {
170        &self.invocation_id
171    }
172
173    /// Get object key.
174    pub fn key(&self) -> &str {
175        &self.key
176    }
177
178    /// Get request headers.
179    pub fn headers(&self) -> &HeaderMap {
180        &self.headers
181    }
182
183    /// Get request headers.
184    pub fn headers_mut(&mut self) -> &HeaderMap {
185        &mut self.headers
186    }
187
188    /// Scope this invocation was submitted with, if any.
189    pub fn scope(&self) -> Option<&str> {
190        self.scope.as_deref()
191    }
192
193    /// Limit key this invocation was submitted with, if any.
194    pub fn limit_key(&self) -> Option<&str> {
195        self.limit_key.as_deref()
196    }
197
198    /// Idempotency key this invocation was submitted with, if any.
199    pub fn idempotency_key(&self) -> Option<&str> {
200        self.idempotency_key.as_deref()
201    }
202}
203
204impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for ObjectContext<'ctx> {
205    fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
206        Self {
207            invocation_id: value.1.invocation_id,
208            key: value.1.key,
209            random_seed: value.1.random_seed,
210            #[cfg(feature = "rand")]
211            std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
212            headers: value.1.headers,
213            scope: value.1.scope,
214            limit_key: value.1.limit_key,
215            idempotency_key: value.1.idempotency_key,
216            inner: value.0,
217        }
218    }
219}
220
221/// Workflow shared handler context.
222pub struct SharedWorkflowContext<'ctx> {
223    invocation_id: String,
224    key: String,
225    random_seed: u64,
226    #[cfg(feature = "rand")]
227    std_rng: rand::prelude::StdRng,
228    headers: HeaderMap,
229    scope: Option<String>,
230    limit_key: Option<String>,
231    idempotency_key: Option<String>,
232    pub(crate) inner: &'ctx ContextInternal,
233}
234
235impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for SharedWorkflowContext<'ctx> {
236    fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
237        Self {
238            invocation_id: value.1.invocation_id,
239            key: value.1.key,
240            random_seed: value.1.random_seed,
241            #[cfg(feature = "rand")]
242            std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
243            headers: value.1.headers,
244            scope: value.1.scope,
245            limit_key: value.1.limit_key,
246            idempotency_key: value.1.idempotency_key,
247            inner: value.0,
248        }
249    }
250}
251
252impl SharedWorkflowContext<'_> {
253    /// Get invocation id.
254    pub fn invocation_id(&self) -> &str {
255        &self.invocation_id
256    }
257
258    /// Get workflow key.
259    pub fn key(&self) -> &str {
260        &self.key
261    }
262
263    /// Get request headers.
264    pub fn headers(&self) -> &HeaderMap {
265        &self.headers
266    }
267
268    /// Get request headers.
269    pub fn headers_mut(&mut self) -> &HeaderMap {
270        &mut self.headers
271    }
272
273    /// Scope this invocation was submitted with, if any.
274    pub fn scope(&self) -> Option<&str> {
275        self.scope.as_deref()
276    }
277
278    /// Limit key this invocation was submitted with, if any.
279    pub fn limit_key(&self) -> Option<&str> {
280        self.limit_key.as_deref()
281    }
282
283    /// Idempotency key this invocation was submitted with, if any.
284    pub fn idempotency_key(&self) -> Option<&str> {
285        self.idempotency_key.as_deref()
286    }
287}
288
289/// Workflow handler context.
290pub struct WorkflowContext<'ctx> {
291    invocation_id: String,
292    key: String,
293    random_seed: u64,
294    #[cfg(feature = "rand")]
295    std_rng: rand::prelude::StdRng,
296    headers: HeaderMap,
297    scope: Option<String>,
298    limit_key: Option<String>,
299    idempotency_key: Option<String>,
300    pub(crate) inner: &'ctx ContextInternal,
301}
302
303impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for WorkflowContext<'ctx> {
304    fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
305        Self {
306            invocation_id: value.1.invocation_id,
307            key: value.1.key,
308            random_seed: value.1.random_seed,
309            #[cfg(feature = "rand")]
310            std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
311            headers: value.1.headers,
312            scope: value.1.scope,
313            limit_key: value.1.limit_key,
314            idempotency_key: value.1.idempotency_key,
315            inner: value.0,
316        }
317    }
318}
319
320impl WorkflowContext<'_> {
321    /// Get invocation id.
322    pub fn invocation_id(&self) -> &str {
323        &self.invocation_id
324    }
325
326    /// Get workflow key.
327    pub fn key(&self) -> &str {
328        &self.key
329    }
330
331    /// Get request headers.
332    pub fn headers(&self) -> &HeaderMap {
333        &self.headers
334    }
335
336    /// Get request headers.
337    pub fn headers_mut(&mut self) -> &HeaderMap {
338        &mut self.headers
339    }
340
341    /// Scope this invocation was submitted with, if any.
342    pub fn scope(&self) -> Option<&str> {
343        self.scope.as_deref()
344    }
345
346    /// Limit key this invocation was submitted with, if any.
347    pub fn limit_key(&self) -> Option<&str> {
348        self.limit_key.as_deref()
349    }
350
351    /// Idempotency key this invocation was submitted with, if any.
352    pub fn idempotency_key(&self) -> Option<&str> {
353        self.idempotency_key.as_deref()
354    }
355}
356
357///
358/// # Scheduling & Timers
359/// The Restate SDK includes durable timers.
360/// You can use these to let handlers sleep for a specified time, or to schedule a handler to be called at a later time.
361/// These timers are resilient to failures and restarts.
362/// Restate stores and keeps track of the timers and triggers them on time, even across failures and restarts.
363///
364/// ## Scheduling Async Tasks
365///
366/// To schedule a handler to be called at a later time, have a look at the documentation on [delayed calls](Request::send_after).
367///
368/// ## Durable sleep
369/// To sleep in a Restate application for ten seconds, do the following:
370///
371/// ```rust,no_run
372/// # use restate_sdk::prelude::*;
373/// # use std::convert::Infallible;
374/// # use std::time::Duration;
375/// #
376/// # async fn handle(ctx: Context<'_>) -> Result<(), HandlerError> {
377/// ctx.sleep(Duration::from_secs(10)).await?;
378/// #    Ok(())
379/// # }
380/// ```
381///
382/// **Cost savings on FaaS**:
383/// Restate suspends the handler while it is sleeping, to free up resources.
384/// This is beneficial for AWS Lambda deployments, since you don't pay for the time the handler is sleeping.
385///
386/// **Sleeping in Virtual Objects**:
387/// Virtual Objects only process a single invocation at a time, so the Virtual Object will be blocked while sleeping.
388///
389/// <details>
390/// <summary>Clock synchronization Restate Server vs. SDK</summary>
391///
392/// The Restate SDK calculates the wake-up time based on the delay you specify.
393/// The Restate Server then uses this calculated time to wake up the handler.
394/// If the Restate Server and the SDK have different system clocks, the sleep duration might not be accurate.
395/// So make sure that the system clock of the Restate Server and the SDK have the same timezone and are synchronized.
396/// </details>
397pub trait ContextTimers<'ctx>: private::SealedContext<'ctx> {
398    /// Sleep using Restate
399    fn sleep(
400        &self,
401        duration: Duration,
402    ) -> impl DurableFuture<Output = Result<(), TerminalError>> + Send + 'ctx {
403        private::SealedContext::inner_context(self).sleep(duration)
404    }
405}
406
407impl<'ctx, CTX: private::SealedContext<'ctx>> ContextTimers<'ctx> for CTX {}
408
409/// # Service Communication
410///
411/// A handler can call another handler and wait for the response (request-response), or it can send a message without waiting for the response.
412///
413/// ## Request-response calls
414///
415/// Request-response calls are requests where the client waits for the response.
416///
417/// You can do request-response calls to Services, Virtual Objects, and Workflows, in the following way:
418///
419/// ```rust,no_run
420/// # #[path = "../../examples/services/mod.rs"]
421/// # mod services;
422/// # use services::my_virtual_object::MyVirtualObjectClient;
423/// # use services::my_service::MyServiceClient;
424/// # use services::my_workflow::MyWorkflowClient;
425/// # use restate_sdk::prelude::*;
426/// #
427/// # async fn greet(ctx: Context<'_>, greeting: String) -> Result<(), HandlerError> {
428///     // To a Service:
429///     let service_response = ctx
430///         .service_client::<MyServiceClient>()
431///         .my_handler(String::from("Hi!"))
432///         .call()
433///         .await?;
434///
435///     // To a Virtual Object:
436///     let object_response = ctx
437///         .object_client::<MyVirtualObjectClient>("Mary")
438///         .my_handler(String::from("Hi!"))
439///         .call()
440///         .await?;
441///
442///     // To a Workflow:
443///     let workflow_result = ctx
444///         .workflow_client::<MyWorkflowClient>("my-workflow-id")
445///         .run(String::from("Hi!"))
446///         .call()
447///         .await?;
448///     ctx.workflow_client::<MyWorkflowClient>("my-workflow-id")
449///         .interact_with_workflow()
450///         .call()
451///         .await?;
452///  #    Ok(())
453///  # }
454/// ```
455///
456/// 1. **Create a service client**.
457///     - For Virtual Objects, you also need to supply the key of the Virtual Object you want to call, here `"Mary"`.
458///     - For Workflows, you need to supply a workflow ID that is unique per workflow execution.
459/// 2. **Specify the handler** you want to call and supply the request.
460/// 3. **Await** the call to retrieve the response.
461///
462/// **No need for manual retry logic**:
463/// Restate proxies all the calls and logs them in the journal.
464/// In case of failures, Restate takes care of retries, so you don't need to implement this yourself here.
465///
466/// ## Idempotency key, scope and concurrency limit key
467///
468/// Calls and sends can carry an idempotency key, a scope, and a concurrency limit key.
469/// A *scope* is a sub-grouping of resources that gets co-located by the restate-server (idempotency
470/// keys are scoped). A *limit key* enforces hierarchical concurrency limits within the scope, and can
471/// only be used together with a scope.
472///
473/// ```rust,no_run
474/// # #[path = "../../examples/services/mod.rs"]
475/// # mod services;
476/// # use services::my_service::MyServiceClient;
477/// # use restate_sdk::prelude::*;
478/// #
479/// # async fn greet(ctx: Context<'_>, greeting: String) -> Result<(), HandlerError> {
480///     ctx.service_client::<MyServiceClient>()
481///         .my_handler(String::from("Hi!"))
482///         .idempotency_key("req-1")
483///         .scope("tenant-123")
484///         .limit_key("api-key/user42")
485///         .call()
486///         .await?;
487/// #    Ok(())
488/// # }
489/// ```
490///
491/// ## Sending messages
492///
493/// Handlers can send messages (a.k.a. one-way calls, or fire-and-forget calls), as follows:
494///
495/// ```rust,no_run
496/// # #[path = "../../examples/services/mod.rs"]
497/// # mod services;
498/// # use services::my_virtual_object::MyVirtualObjectClient;
499/// # use services::my_service::MyServiceClient;
500/// # use services::my_workflow::MyWorkflowClient;
501/// # use restate_sdk::prelude::*;
502/// #
503/// # async fn greet(ctx: Context<'_>, greeting: String) -> Result<(), HandlerError> {
504///     // To a Service:
505///     ctx.service_client::<MyServiceClient>()
506///         .my_handler(String::from("Hi!"))
507///         .send();
508///
509///     // To a Virtual Object:
510///     ctx.object_client::<MyVirtualObjectClient>("Mary")
511///         .my_handler(String::from("Hi!"))
512///         .send();
513///
514///     // To a Workflow:
515///     ctx.workflow_client::<MyWorkflowClient>("my-workflow-id")
516///         .run(String::from("Hi!"))
517///         .send();
518///     ctx.workflow_client::<MyWorkflowClient>("my-workflow-id")
519///         .interact_with_workflow()
520///         .send();
521///  #    Ok(())
522///  # }
523/// ```
524///
525/// **No need for message queues**:
526/// Without Restate, you would usually put a message queue in between the two services, to guarantee the message delivery.
527/// Restate eliminates the need for a message queue because Restate durably logs the request and makes sure it gets executed.
528///
529/// ## Delayed calls
530///
531/// A delayed call is a one-way call that gets executed after a specified delay.
532///
533/// To schedule a delayed call, send a message with a delay parameter, as follows:
534///
535/// ```rust,no_run
536/// # #[path = "../../examples/services/mod.rs"]
537/// # mod services;
538/// # use services::my_virtual_object::MyVirtualObjectClient;
539/// # use services::my_service::MyServiceClient;
540/// # use services::my_workflow::MyWorkflowClient;
541/// # use restate_sdk::prelude::*;
542/// # use std::time::Duration;
543/// #
544/// # async fn greet(ctx: Context<'_>, greeting: String) -> Result<(), HandlerError> {
545///     // To a Service:
546///     ctx.service_client::<MyServiceClient>()
547///         .my_handler(String::from("Hi!"))
548///         .send_after(Duration::from_millis(5000));
549///
550///     // To a Virtual Object:
551///     ctx.object_client::<MyVirtualObjectClient>("Mary")
552///         .my_handler(String::from("Hi!"))
553///         .send_after(Duration::from_millis(5000));
554///
555///     // To a Workflow:
556///     ctx.workflow_client::<MyWorkflowClient>("my-workflow-id")
557///         .run(String::from("Hi!"))
558///         .send_after(Duration::from_millis(5000));
559///     ctx.workflow_client::<MyWorkflowClient>("my-workflow-id")
560///         .interact_with_workflow()
561///         .send_after(Duration::from_millis(5000));
562///  #    Ok(())
563///  # }
564/// ```
565///
566/// You can also use this functionality to schedule async tasks.
567/// Restate will make sure the task gets executed at the desired time.
568///
569/// ### Ordering guarantees in Virtual Objects
570/// Invocations to a Virtual Object are executed serially.
571/// Invocations will execute in the same order in which they arrive at Restate.
572/// For example, assume a handler calls the same Virtual Object twice:
573///
574/// ```rust,no_run
575/// # #[path = "../../examples/services/my_virtual_object.rs"]
576/// # mod my_virtual_object;
577/// # use my_virtual_object::MyVirtualObjectClient;
578/// # use restate_sdk::prelude::*;
579/// # async fn greet(ctx: Context<'_>, greeting: String) -> Result<(), HandlerError> {
580///     ctx.object_client::<MyVirtualObjectClient>("Mary")
581///         .my_handler(String::from("I'm call A!"))
582///         .send();
583///     ctx.object_client::<MyVirtualObjectClient>("Mary")
584///         .my_handler(String::from("I'm call B!"))
585///         .send();
586/// #    Ok(())
587/// }
588/// ```
589///
590/// It is guaranteed that call A will execute before call B.
591/// It is not guaranteed though that call B will be executed immediately after call A, as invocations coming from other handlers/sources, could interleave these two calls.
592///
593/// ### Deadlocks with Virtual Objects
594/// Request-response calls to Virtual Objects can lead to deadlocks, in which the Virtual Object remains locked and can't process any more requests.
595/// Some example cases:
596/// - Cross deadlock between Virtual Object A and B: A calls B, and B calls A, both using same keys.
597/// - Cyclical deadlock: A calls B, and B calls C, and C calls A again.
598///
599/// In this situation, you can use the CLI to unblock the Virtual Object manually by [cancelling invocations](https://docs.restate.dev/operate/invocation#cancelling-invocations).
600///
601pub trait ContextClient<'ctx>: private::SealedContext<'ctx> {
602    /// Create a [`Request`].
603    fn request<Req, Res>(
604        &self,
605        request_target: RequestTarget,
606        req: Req,
607    ) -> Request<'ctx, Req, Res> {
608        Request::new(self.inner_context(), request_target, req)
609    }
610
611    /// Create an [`InvocationHandle`] from an invocation id.
612    fn invocation_handle(&self, invocation_id: String) -> InvocationHandle {
613        self.inner_context().invocation_handle(invocation_id)
614    }
615
616    /// Create a service client. The service client is generated by the [`restate_sdk_macros::service`] macro with the same name of the trait suffixed with `Client`.
617    ///
618    /// ```rust,no_run
619    /// # use std::time::Duration;
620    /// # use restate_sdk::prelude::*;
621    ///
622    /// #[restate_sdk::service]
623    /// trait MyService {
624    ///   async fn handle() -> HandlerResult<()>;
625    /// }
626    ///
627    /// # async fn handler(ctx: Context<'_>) {
628    /// let client = ctx.service_client::<MyServiceClient>();
629    ///
630    /// // Do request
631    /// let result = client.handle().call().await;
632    ///
633    /// // Just send the request, don't wait the response
634    /// client.handle().send();
635    ///
636    /// // Schedule the request to be executed later
637    /// client.handle().send_after(Duration::from_secs(60));
638    /// # }
639    /// ```
640    fn service_client<C>(&self) -> C
641    where
642        C: IntoServiceClient<'ctx>,
643    {
644        C::create_client(self.inner_context())
645    }
646
647    /// Create an object client. The object client is generated by the [`restate_sdk_macros::object`] macro with the same name of the trait suffixed with `Client`.
648    ///
649    /// ```rust,no_run
650    /// # use std::time::Duration;
651    /// # use restate_sdk::prelude::*;
652    ///
653    /// #[restate_sdk::object]
654    /// trait MyObject {
655    ///   async fn handle() -> HandlerResult<()>;
656    /// }
657    ///
658    /// # async fn handler(ctx: Context<'_>) {
659    /// let client = ctx.object_client::<MyObjectClient>("my-key");
660    ///
661    /// // Do request
662    /// let result = client.handle().call().await;
663    ///
664    /// // Just send the request, don't wait the response
665    /// client.handle().send();
666    ///
667    /// // Schedule the request to be executed later
668    /// client.handle().send_after(Duration::from_secs(60));
669    /// # }
670    /// ```
671    fn object_client<C>(&self, key: impl Into<String>) -> C
672    where
673        C: IntoObjectClient<'ctx>,
674    {
675        C::create_client(self.inner_context(), key.into())
676    }
677
678    /// Create an workflow client. The workflow client is generated by the [`restate_sdk_macros::workflow`] macro with the same name of the trait suffixed with `Client`.
679    ///
680    /// ```rust,no_run
681    /// # use std::time::Duration;
682    /// # use restate_sdk::prelude::*;
683    ///
684    /// #[restate_sdk::workflow]
685    /// trait MyWorkflow {
686    ///   async fn handle() -> HandlerResult<()>;
687    /// }
688    ///
689    /// # async fn handler(ctx: Context<'_>) {
690    /// let client = ctx.workflow_client::<MyWorkflowClient>("my-key");
691    ///
692    /// // Do request
693    /// let result = client.handle().call().await;
694    ///
695    /// // Just send the request, don't wait the response
696    /// client.handle().send();
697    ///
698    /// // Schedule the request to be executed later
699    /// client.handle().send_after(Duration::from_secs(60));
700    /// # }
701    /// ```
702    fn workflow_client<C>(&self, key: impl Into<String>) -> C
703    where
704        C: IntoWorkflowClient<'ctx>,
705    {
706        C::create_client(self.inner_context(), key.into())
707    }
708}
709
710/// Trait used by codegen to create the service client.
711pub trait IntoServiceClient<'ctx>: Sized {
712    fn create_client(ctx: &'ctx ContextInternal) -> Self;
713}
714
715/// Trait used by codegen to use the object client.
716pub trait IntoObjectClient<'ctx>: Sized {
717    fn create_client(ctx: &'ctx ContextInternal, key: String) -> Self;
718}
719
720/// Trait used by codegen to use the workflow client.
721pub trait IntoWorkflowClient<'ctx>: Sized {
722    fn create_client(ctx: &'ctx ContextInternal, key: String) -> Self;
723}
724
725impl<'ctx, CTX: private::SealedContext<'ctx>> ContextClient<'ctx> for CTX {}
726
727/// # Awakeables
728///
729/// Awakeables pause an invocation while waiting for another process to complete a task.
730/// You can use this pattern to let a handler execute a task somewhere else and retrieve the result.
731/// This pattern is also known as the callback (task token) pattern.
732///
733/// ## Creating awakeables
734///
735/// 1. **Create an awakeable**. This contains a String identifier and a Promise.
736/// 2. **Trigger a task/process** and attach the awakeable ID (e.g., over Kafka, via HTTP, ...).
737///    For example, send an HTTP request to a service that executes the task, and attach the ID to the payload.
738///    You use `ctx.run` to avoid re-triggering the task on retries.
739/// 3. **Wait** until the other process has executed the task.
740///    The handler **receives the payload and resumes**.
741///
742/// ```rust,no_run
743/// # use restate_sdk::prelude::*;
744/// #
745/// # async fn handle(ctx: Context<'_>) -> Result<(), HandlerError> {
746/// /// 1. Create an awakeable
747/// let (id, promise) = ctx.awakeable::<String>();
748///
749/// /// 2. Trigger a task
750/// ctx.run(|| trigger_task_and_deliver_id(id.clone())).await?;
751///
752/// /// 3. Wait for the promise to be resolved
753/// let payload = promise.await?;
754/// # Ok(())
755/// # }
756/// # async fn trigger_task_and_deliver_id(awakeable_id: String) -> Result<(), HandlerError>{
757/// #    Ok(())
758/// # }
759/// ```
760///
761///
762/// ## Completing awakeables
763///
764/// The external process completes the awakeable by either resolving it with an optional payload or by rejecting it
765/// with its ID and a reason for the failure. This throws [a terminal error][crate::errors] in the waiting handler.
766///
767/// - Resolving over HTTP with its ID and an optional payload:
768///
769/// ```text
770/// curl localhost:8080/restate/awakeables/prom_1PePOqp/resolve
771///     -H 'content-type: application/json'
772///     -d '{"hello": "world"}'
773/// ```
774///
775/// - Rejecting over HTTP with its ID and a reason:
776///
777/// ```text
778/// curl localhost:8080/restate/awakeables/prom_1PePOqp/reject
779///     -H 'content-type: text/plain' \
780///     -d 'Very bad error!'
781/// ```
782///
783/// - Resolving via the SDK with its ID and an optional payload, or rejecting with its ID and a reason:
784///
785/// ```rust,no_run
786/// # use restate_sdk::prelude::*;
787/// #
788/// # async fn handle(ctx: Context<'_>, id: String) -> Result<(), HandlerError> {
789/// // Resolve the awakeable
790/// ctx.resolve_awakeable(&id, "hello".to_string());
791///
792/// // Or reject the awakeable
793/// ctx.reject_awakeable(&id, TerminalError::new("my error reason"));
794/// # Ok(())
795/// # }
796/// ```
797///
798/// For more info about serialization of the payload, see [crate::serde]
799///
800/// When running on Function-as-a-Service platforms, such as AWS Lambda, Restate suspends the handler while waiting for the awakeable to be completed.
801/// Since you only pay for the time that the handler is actually running, you don't pay while waiting for the external process to return.
802///
803/// **Be aware**: Virtual Objects only process a single invocation at a time, so the Virtual Object will be blocked while waiting on the awakeable to be resolved.
804pub trait ContextAwakeables<'ctx>: private::SealedContext<'ctx> {
805    /// Create an awakeable
806    fn awakeable<T: Deserialize + 'static>(
807        &self,
808    ) -> (
809        String,
810        impl DurableFuture<Output = Result<T, TerminalError>> + Send + 'ctx,
811    ) {
812        self.inner_context().awakeable()
813    }
814
815    /// Resolve an awakeable
816    fn resolve_awakeable<T: Serialize + 'static>(&self, key: &str, t: T) {
817        self.inner_context().resolve_awakeable(key, t)
818    }
819
820    /// Resolve an awakeable
821    fn reject_awakeable(&self, key: &str, failure: TerminalError) {
822        self.inner_context().reject_awakeable(key, failure)
823    }
824}
825
826impl<'ctx, CTX: private::SealedContext<'ctx>> ContextAwakeables<'ctx> for CTX {}
827
828/// # Signals
829///
830/// Signals let invocations communicate with each other. A signal is a named, one-shot
831/// durable promise **scoped to a specific invocation**: a running handler awaits a signal by name,
832/// and any other handler completes it by targeting the awaiter's **invocation id** and the same
833/// **signal name**.
834///
835/// Signals are similar to [awakeables][crate::context::ContextAwakeables], but instead of an
836/// opaque generated identifier you exfiltrate, they are addressed by `(invocation_id, name)`.
837/// The awaiting handler just needs to share its own invocation id (available via
838/// [`Context::invocation_id`]).
839///
840/// ## Awaiting a signal
841///
842/// ```rust,no_run
843/// # use restate_sdk::prelude::*;
844/// # async fn handle(ctx: Context<'_>) -> Result<(), HandlerError> {
845/// // Wait for a named signal on the current invocation
846/// let value = ctx.signal::<String>("my-signal").await?;
847/// # Ok(())
848/// # }
849/// ```
850///
851/// The returned future is a [`DurableFuture`], so it can be combined with other durable futures
852/// using [`crate::select`].
853///
854/// ## Completing a signal
855///
856/// Another handler completes the signal on the target invocation using its
857/// [`InvocationHandle`][crate::context::InvocationHandle]:
858///
859/// ```rust,no_run
860/// # use restate_sdk::prelude::*;
861/// // Resolve the signal with a value
862/// # async fn resolve(ctx: Context<'_>, invocation_id: String) -> Result<(), HandlerError> {
863/// ctx.invocation_handle(invocation_id)
864///     .signal("my-signal")
865///     .resolve("hello".to_string());
866/// # Ok(())
867/// # }
868///
869/// // Or reject it, so the awaiting handler observes a terminal error
870/// # async fn reject(ctx: Context<'_>, invocation_id: String) -> Result<(), HandlerError> {
871/// ctx.invocation_handle(invocation_id)
872///     .signal("my-signal")
873///     .reject(TerminalError::new("my error reason"));
874/// # Ok(())
875/// # }
876/// ```
877///
878/// For more info about serialization of the payload, see [crate::serde].
879///
880/// **Be aware**: Virtual Objects only process a single invocation at a time, so the Virtual Object
881/// will be blocked while waiting on the signal to be completed.
882pub trait ContextSignals<'ctx>: private::SealedContext<'ctx> {
883    /// Wait for a named signal to arrive on the current invocation.
884    ///
885    /// Signals are identified by name and are scoped to the current invocation. Another handler
886    /// can complete this signal via [`InvocationHandle::signal`][crate::context::InvocationHandle::signal],
887    /// specifying this invocation's id (available via [`Context::invocation_id`]) and the same name.
888    fn signal<T: Deserialize + 'static>(
889        &self,
890        name: &str,
891    ) -> impl DurableFuture<Output = Result<T, TerminalError>> + Send + 'ctx {
892        self.inner_context().signal(name)
893    }
894}
895
896impl<'ctx, CTX: private::SealedContext<'ctx>> ContextSignals<'ctx> for CTX {}
897
898/// # Journaling Results
899///
900/// Restate uses an execution log for replay after failures and suspensions.
901/// This means that non-deterministic results (e.g. database responses, UUID generation) need to be stored in the execution log.
902/// The SDK offers some functionalities to help you with this:
903/// 1. **[Journaled actions][crate::context::ContextSideEffects::run]**: Run any block of code and store the result in Restate. Restate replays the result instead of re-executing the block on retries.
904/// 2. **[UUID generator][crate::context::ContextSideEffects::rand_uuid]**: Built-in helpers for generating stable UUIDs. Restate seeds the random number generator with the invocation ID, so it always returns the same value on retries.
905/// 3. **[Random generator][crate::context::ContextSideEffects::rand]**: Built-in helpers for generating randoms. Restate seeds the random number generator with the invocation ID, so it always returns the same value on retries.
906///
907pub trait ContextSideEffects<'ctx>: private::SealedContext<'ctx> {
908    /// ## Journaled actions
909    /// You can store the result of a (non-deterministic) operation in the Restate execution log (e.g. database requests, HTTP calls, etc).
910    /// Restate replays the result instead of re-executing the operation on retries.
911    ///
912    /// Here is an example of a database request for which the string response is stored in Restate:
913    /// ```rust,no_run
914    /// # use restate_sdk::prelude::*;
915    /// # async fn handle(ctx: Context<'_>) -> Result<(), HandlerError> {
916    /// let response = ctx.run(|| do_db_request()).await?;
917    /// # Ok(())
918    /// # }
919    /// # async fn do_db_request() -> Result<String, HandlerError>{
920    /// # Ok("Hello".to_string())
921    /// # }
922    /// ```
923    ///
924    /// You cannot use the Restate context within `ctx.run`.
925    /// This includes actions such as getting state, calling another service, and nesting other journaled actions.
926    ///
927    /// For more info about serialization of the return values, see [crate::serde].
928    ///
929    /// You can configure the retry policy for the `ctx.run` block:
930    /// ```rust,no_run
931    /// # use std::time::Duration;
932    /// # use restate_sdk::prelude::*;
933    /// # async fn handle(ctx: Context<'_>) -> Result<(), HandlerError> {
934    /// let my_run_retry_policy = RunRetryPolicy::default()
935    ///     .initial_delay(Duration::from_millis(100))
936    ///     .exponentiation_factor(2.0)
937    ///     .max_delay(Duration::from_millis(1000))
938    ///     .max_attempts(10)
939    ///     .max_duration(Duration::from_secs(10));
940    /// ctx.run(|| write_to_other_system())
941    ///     .retry_policy(my_run_retry_policy)
942    ///     .await
943    ///     .map_err(|e| {
944    ///         // Handle the terminal error after retries exhausted
945    ///         // For example, undo previous actions (see sagas guide) and
946    ///         // propagate the error back to the caller
947    ///         e
948    ///      })?;
949    /// # Ok(())
950    /// # }
951    /// # async fn write_to_other_system() -> Result<String, HandlerError>{
952    /// # Ok("Hello".to_string())
953    /// # }
954    /// ```
955    ///
956    /// This way you can override the default retry behavior of your Restate service for specific operations.
957    /// Have a look at [`RunFuture::retry_policy`] for more information.
958    ///
959    /// If you set a maximum number of attempts, then the `ctx.run` block will fail with a [TerminalError] once the retries are exhausted.
960    /// Have a look at the [Sagas guide](https://docs.restate.dev/guides/sagas) to learn how to undo previous actions of the handler to keep the system in a consistent state.
961    ///
962    /// **Caution: Immediately await journaled actions:**
963    /// Always immediately await `ctx.run`, before doing any other context calls.
964    /// If not, you might bump into non-determinism errors during replay,
965    /// because the journaled result can get interleaved with the other context calls in the journal in a non-deterministic way.
966    ///
967    #[must_use]
968    fn run<R, F, T>(&self, run_closure: R) -> impl RunFuture<Result<T, TerminalError>> + 'ctx
969    where
970        R: RunClosure<Fut = F, Output = T> + Send + 'ctx,
971        F: Future<Output = HandlerResult<T>> + Send + 'ctx,
972        T: Serialize + Deserialize + 'static,
973    {
974        self.inner_context().run(run_closure)
975    }
976
977    /// Return a random seed inherently predictable, based on the invocation id, which is not secret.
978    ///
979    /// This value is stable during the invocation lifecycle, thus across retries.
980    fn random_seed(&self) -> u64 {
981        private::SealedContext::random_seed(self)
982    }
983
984    /// ### Generating random numbers
985    ///
986    /// Return a [`rand::RngExt`] instance inherently predictable, seeded with [`ContextSideEffects::random_seed`].
987    ///
988    /// ```rust,no_run
989    /// # use restate_sdk::prelude::*;
990    /// async fn rand_generate(mut ctx: Context<'_>) {
991    /// let x: u32 = ctx.rand().random();
992    /// # }
993    /// ```
994    ///
995    /// This instance is useful to generate identifiers, idempotency keys, and for uniform sampling from a set of options.
996    /// If a cryptographically secure value is needed, please generate that externally using [`ContextSideEffects::run`].
997    #[cfg(feature = "rand")]
998    fn rand(&mut self) -> &mut rand::prelude::StdRng {
999        private::SealedContext::rand(self)
1000    }
1001    /// ### Generating UUIDs
1002    ///
1003    /// Returns a random [`uuid::Uuid`], generated using [`ContextSideEffects::rand`].
1004    ///
1005    /// You can use these UUIDs to generate stable idempotency keys, to deduplicate operations. For example, you can use this to let a payment service avoid duplicate payments during retries.
1006    ///
1007    /// Do not use this in cryptographic contexts.
1008    ///
1009    /// ```rust,no_run
1010    /// # use restate_sdk::prelude::*;
1011    /// # use uuid::Uuid;
1012    /// # async fn uuid_generate(mut ctx: Context<'_>) {
1013    /// let uuid: Uuid = ctx.rand_uuid();
1014    /// # }
1015    /// ```
1016    #[cfg(all(feature = "rand", feature = "uuid"))]
1017    fn rand_uuid(&mut self) -> uuid::Uuid {
1018        let rand = private::SealedContext::rand(self);
1019        uuid::Uuid::from_u64_pair(rand::Rng::next_u64(rand), rand::Rng::next_u64(rand))
1020    }
1021}
1022
1023impl<'ctx, CTX: private::SealedContext<'ctx>> ContextSideEffects<'ctx> for CTX {}
1024
1025/// # Reading state
1026/// You can store key-value state in Restate.
1027/// Restate makes sure the state is consistent with the processing of the code execution.
1028///
1029/// **This feature is only available for Virtual Objects and Workflows:**
1030/// - For **Virtual Objects**, the state is isolated per Virtual Object and lives forever (across invocations for that object).
1031/// - For **Workflows**, you can think of it as if every workflow execution is a new object. So the state is isolated to a single workflow execution. The state can only be mutated by the `run` handler of the workflow. The other handlers can only read the state.
1032///
1033/// ```rust,no_run
1034/// # use restate_sdk::prelude::*;
1035/// #
1036/// # async fn my_handler(ctx: ObjectContext<'_>) -> Result<(), HandlerError> {
1037///     /// 1. Listing state keys
1038///     /// List all the state keys that have entries in the state store for this object, via:
1039///     let keys = ctx.get_keys().await?;
1040///
1041///     /// 2. Getting a state value
1042///     let my_string = ctx
1043///         .get::<String>("my-key")
1044///         .await?
1045///         .unwrap_or(String::from("my-default"));
1046///     let my_number = ctx.get::<f64>("my-number-key").await?.unwrap_or_default();
1047///
1048///     /// 3. Setting a state value
1049///     ctx.set("my-key", String::from("my-value"));
1050///
1051///     /// 4. Clearing a state value
1052///     ctx.clear("my-key");
1053///
1054///     /// 5. Clearing all state values
1055///     /// Deletes all the state in Restate for the object
1056///     ctx.clear_all();
1057/// #    Ok(())
1058/// # }
1059/// ```
1060///
1061/// For more info about serialization, see [crate::serde]
1062///
1063/// ### Command-line introspection
1064/// You can inspect and edit the K/V state stored in Restate via `psql` and the CLI.
1065/// Have a look at the [introspection docs](https://docs.restate.dev//operate/introspection#inspecting-application-state) for more information.
1066///
1067pub trait ContextReadState<'ctx>: private::SealedContext<'ctx> {
1068    /// Get state
1069    fn get<T: Deserialize + 'static>(
1070        &self,
1071        key: &'ctx str,
1072    ) -> impl Future<Output = Result<Option<T>, TerminalError>> + 'ctx {
1073        self.inner_context().get(key)
1074    }
1075
1076    /// Get state keys
1077    fn get_keys(&'ctx self) -> impl Future<Output = Result<Vec<String>, TerminalError>> + 'ctx {
1078        self.inner_context().get_keys()
1079    }
1080}
1081
1082impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanReadState> ContextReadState<'ctx>
1083    for CTX
1084{
1085}
1086
1087/// # Writing State
1088/// You can store key-value state in Restate.
1089/// Restate makes sure the state is consistent with the processing of the code execution.
1090///
1091/// **This feature is only available for Virtual Objects and Workflows:**
1092/// - For **Virtual Objects**, the state is isolated per Virtual Object and lives forever (across invocations for that object).
1093/// - For **Workflows**, you can think of it as if every workflow execution is a new object. So the state is isolated to a single workflow execution. The state can only be mutated by the `run` handler of the workflow. The other handlers can only read the state.
1094///
1095/// ```rust,no_run
1096/// # use restate_sdk::prelude::*;
1097/// #
1098/// # async fn my_handler(ctx: ObjectContext<'_>) -> Result<(), HandlerError> {
1099///     /// 1. Listing state keys
1100///     /// List all the state keys that have entries in the state store for this object, via:
1101///     let keys = ctx.get_keys().await?;
1102///
1103///     /// 2. Getting a state value
1104///     let my_string = ctx
1105///         .get::<String>("my-key")
1106///         .await?
1107///         .unwrap_or(String::from("my-default"));
1108///     let my_number = ctx.get::<f64>("my-number-key").await?.unwrap_or_default();
1109///
1110///     /// 3. Setting a state value
1111///     ctx.set("my-key", String::from("my-value"));
1112///
1113///     /// 4. Clearing a state value
1114///     ctx.clear("my-key");
1115///
1116///     /// 5. Clearing all state values
1117///     /// Deletes all the state in Restate for the object
1118///     ctx.clear_all();
1119/// #    Ok(())
1120/// # }
1121/// ```
1122///
1123/// For more info about serialization, see [crate::serde]
1124///
1125/// ## Command-line introspection
1126/// You can inspect and edit the K/V state stored in Restate via `psql` and the CLI.
1127/// Have a look at the [introspection docs](https://docs.restate.dev//operate/introspection#inspecting-application-state) for more information.
1128///
1129pub trait ContextWriteState<'ctx>: private::SealedContext<'ctx> {
1130    /// Set state
1131    fn set<T: Serialize + 'static>(&self, key: &str, t: T) {
1132        self.inner_context().set(key, t)
1133    }
1134
1135    /// Clear state
1136    fn clear(&self, key: &str) {
1137        self.inner_context().clear(key)
1138    }
1139
1140    /// Clear all state
1141    fn clear_all(&self) {
1142        self.inner_context().clear_all()
1143    }
1144}
1145
1146impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanWriteState> ContextWriteState<'ctx>
1147    for CTX
1148{
1149}
1150
1151/// Trait exposing Restate promise functionalities.
1152///
1153/// A promise is a durable, distributed version of a Rust oneshot channel.
1154/// Restate keeps track of the promises across restarts/failures.
1155///
1156/// You can use this feature to implement interaction between different workflow handlers, e.g. to
1157/// send a signal from a shared handler to the workflow handler.
1158pub trait ContextPromises<'ctx>: private::SealedContext<'ctx> {
1159    /// Create a promise
1160    fn promise<T: Deserialize + 'static>(
1161        &'ctx self,
1162        key: &'ctx str,
1163    ) -> impl DurableFuture<Output = Result<T, TerminalError>> + 'ctx {
1164        self.inner_context().promise(key)
1165    }
1166
1167    /// Peek a promise
1168    fn peek_promise<T: Deserialize + 'static>(
1169        &self,
1170        key: &'ctx str,
1171    ) -> impl Future<Output = Result<Option<T>, TerminalError>> + 'ctx {
1172        self.inner_context().peek_promise(key)
1173    }
1174
1175    /// Resolve a promise
1176    fn resolve_promise<T: Serialize + 'static>(&self, key: &str, t: T) {
1177        self.inner_context().resolve_promise(key, t)
1178    }
1179
1180    /// Resolve a promise
1181    fn reject_promise(&self, key: &str, failure: TerminalError) {
1182        self.inner_context().reject_promise(key, failure)
1183    }
1184}
1185
1186impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanUsePromises> ContextPromises<'ctx>
1187    for CTX
1188{
1189}
1190
1191/// A future returned by a Restate operation, which can participate in combinators such as
1192/// [`select!`](crate::select) and [`DurableFuturesUnordered`].
1193///
1194/// The [`map`](DurableFuture::map)/[`map_ok`](DurableFuture::map_ok)/[`map_err`](DurableFuture::map_err)
1195/// combinators transform the output while keeping the result a [`DurableFuture`], so it can still be
1196/// used in combinators.
1197pub trait DurableFuture: Future + macro_support::SealedDurableFuture {
1198    /// Map the output of this durable future.
1199    fn map<U, M>(self, mapper: M) -> MapDurableFuture<Self, M>
1200    where
1201        Self: Sized,
1202        M: FnOnce(Self::Output) -> U,
1203    {
1204        MapDurableFuture::new(self, mapper)
1205    }
1206
1207    /// Map the success value of this durable future, leaving terminal errors untouched.
1208    fn map_ok<T, U, M>(self, mapper: M) -> MapOkDurableFuture<Self, M>
1209    where
1210        Self: Sized + Future<Output = Result<T, TerminalError>>,
1211        M: FnOnce(T) -> U,
1212    {
1213        MapOkDurableFuture::new(self, mapper)
1214    }
1215
1216    /// Map the terminal error of this durable future, leaving success values untouched.
1217    fn map_err<T, M>(self, mapper: M) -> MapErrDurableFuture<Self, M>
1218    where
1219        Self: Sized + Future<Output = Result<T, TerminalError>>,
1220        M: FnOnce(TerminalError) -> TerminalError,
1221    {
1222        MapErrDurableFuture::new(self, mapper)
1223    }
1224}
1225
1226impl<'a, O> macro_support::SealedDurableFuture
1227    for std::pin::Pin<Box<dyn DurableFuture<Output = O> + Send + 'a>>
1228{
1229    fn inner_context(&self) -> ContextInternal {
1230        (**self).inner_context()
1231    }
1232
1233    fn handle(&self) -> restate_sdk_shared_core::NotificationHandle {
1234        (**self).handle()
1235    }
1236}
1237
1238impl<'a, O> DurableFuture for std::pin::Pin<Box<dyn DurableFuture<Output = O> + Send + 'a>> {}
1239
1240pub(crate) mod private {
1241    use super::*;
1242    pub trait SealedContext<'ctx> {
1243        fn inner_context(&self) -> &'ctx ContextInternal;
1244
1245        fn random_seed(&self) -> u64;
1246
1247        #[cfg(feature = "rand")]
1248        fn rand(&mut self) -> &mut rand::prelude::StdRng;
1249    }
1250
1251    // Context capabilities
1252    pub trait SealedCanReadState {}
1253    pub trait SealedCanWriteState {}
1254    pub trait SealedCanUsePromises {}
1255
1256    impl<'ctx> SealedContext<'ctx> for Context<'ctx> {
1257        fn inner_context(&self) -> &'ctx ContextInternal {
1258            self.inner
1259        }
1260
1261        fn random_seed(&self) -> u64 {
1262            self.random_seed
1263        }
1264
1265        #[cfg(feature = "rand")]
1266        fn rand(&mut self) -> &mut rand::prelude::StdRng {
1267            &mut self.std_rng
1268        }
1269    }
1270
1271    impl<'ctx> SealedContext<'ctx> for SharedObjectContext<'ctx> {
1272        fn inner_context(&self) -> &'ctx ContextInternal {
1273            self.inner
1274        }
1275
1276        fn random_seed(&self) -> u64 {
1277            self.random_seed
1278        }
1279
1280        #[cfg(feature = "rand")]
1281        fn rand(&mut self) -> &mut rand::prelude::StdRng {
1282            &mut self.std_rng
1283        }
1284    }
1285
1286    impl SealedCanReadState for SharedObjectContext<'_> {}
1287
1288    impl<'ctx> SealedContext<'ctx> for ObjectContext<'ctx> {
1289        fn inner_context(&self) -> &'ctx ContextInternal {
1290            self.inner
1291        }
1292
1293        fn random_seed(&self) -> u64 {
1294            self.random_seed
1295        }
1296
1297        #[cfg(feature = "rand")]
1298        fn rand(&mut self) -> &mut rand::prelude::StdRng {
1299            &mut self.std_rng
1300        }
1301    }
1302
1303    impl SealedCanReadState for ObjectContext<'_> {}
1304    impl SealedCanWriteState for ObjectContext<'_> {}
1305
1306    impl<'ctx> SealedContext<'ctx> for SharedWorkflowContext<'ctx> {
1307        fn inner_context(&self) -> &'ctx ContextInternal {
1308            self.inner
1309        }
1310
1311        fn random_seed(&self) -> u64 {
1312            self.random_seed
1313        }
1314
1315        #[cfg(feature = "rand")]
1316        fn rand(&mut self) -> &mut rand::prelude::StdRng {
1317            &mut self.std_rng
1318        }
1319    }
1320
1321    impl SealedCanReadState for SharedWorkflowContext<'_> {}
1322    impl SealedCanUsePromises for SharedWorkflowContext<'_> {}
1323
1324    impl<'ctx> SealedContext<'ctx> for WorkflowContext<'ctx> {
1325        fn inner_context(&self) -> &'ctx ContextInternal {
1326            self.inner
1327        }
1328
1329        fn random_seed(&self) -> u64 {
1330            self.random_seed
1331        }
1332
1333        #[cfg(feature = "rand")]
1334        fn rand(&mut self) -> &mut rand::prelude::StdRng {
1335            &mut self.std_rng
1336        }
1337    }
1338
1339    impl SealedCanReadState for WorkflowContext<'_> {}
1340    impl SealedCanWriteState for WorkflowContext<'_> {}
1341    impl SealedCanUsePromises for WorkflowContext<'_> {}
1342}