restate_sdk/context/
request.rs

1use super::DurableFuture;
2
3use crate::endpoint::ContextInternal;
4use crate::errors::TerminalError;
5use crate::serde::{Deserialize, Serialize};
6use std::fmt;
7use std::future::Future;
8use std::marker::PhantomData;
9use std::time::Duration;
10
11/// Target of a request to a Restate service.
12#[derive(Debug, Clone)]
13pub enum RequestTarget {
14    Service {
15        name: String,
16        handler: String,
17    },
18    Object {
19        name: String,
20        key: String,
21        handler: String,
22    },
23    Workflow {
24        name: String,
25        key: String,
26        handler: String,
27    },
28}
29
30impl RequestTarget {
31    pub fn service(name: impl Into<String>, handler: impl Into<String>) -> Self {
32        Self::Service {
33            name: name.into(),
34            handler: handler.into(),
35        }
36    }
37
38    pub fn object(
39        name: impl Into<String>,
40        key: impl Into<String>,
41        handler: impl Into<String>,
42    ) -> Self {
43        Self::Object {
44            name: name.into(),
45            key: key.into(),
46            handler: handler.into(),
47        }
48    }
49
50    pub fn workflow(
51        name: impl Into<String>,
52        key: impl Into<String>,
53        handler: impl Into<String>,
54    ) -> Self {
55        Self::Workflow {
56            name: name.into(),
57            key: key.into(),
58            handler: handler.into(),
59        }
60    }
61}
62
63impl fmt::Display for RequestTarget {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        match self {
66            RequestTarget::Service { name, handler } => write!(f, "{name}/{handler}"),
67            RequestTarget::Object { name, key, handler } => write!(f, "{name}/{key}/{handler}"),
68            RequestTarget::Workflow { name, key, handler } => write!(f, "{name}/{key}/{handler}"),
69        }
70    }
71}
72
73/// This struct encapsulates the parameters for a request to a service.
74pub struct Request<'a, Req, Res = ()> {
75    ctx: &'a ContextInternal,
76    request_target: RequestTarget,
77    idempotency_key: Option<String>,
78    headers: Vec<(String, String)>,
79    req: Req,
80    res: PhantomData<Res>,
81}
82
83impl<'a, Req, Res> Request<'a, Req, Res> {
84    pub(crate) fn new(ctx: &'a ContextInternal, request_target: RequestTarget, req: Req) -> Self {
85        Self {
86            ctx,
87            request_target,
88            idempotency_key: None,
89            headers: vec![],
90            req,
91            res: PhantomData,
92        }
93    }
94
95    pub fn header(mut self, key: String, value: String) -> Self {
96        self.headers.push((key, value));
97        self
98    }
99
100    /// Add idempotency key to the request
101    pub fn idempotency_key(mut self, idempotency_key: impl Into<String>) -> Self {
102        self.idempotency_key = Some(idempotency_key.into());
103        self
104    }
105
106    /// Call a service. This returns a future encapsulating the response.
107    pub fn call(self) -> impl CallFuture<Response = Res> + Send
108    where
109        Req: Serialize + 'static,
110        Res: Deserialize + 'static,
111    {
112        self.ctx.call(
113            self.request_target,
114            self.idempotency_key,
115            self.headers,
116            self.req,
117        )
118    }
119
120    /// Send the request to the service, without waiting for the response.
121    pub fn send(self) -> impl InvocationHandle
122    where
123        Req: Serialize + 'static,
124    {
125        self.ctx.send(
126            self.request_target,
127            self.idempotency_key,
128            self.headers,
129            self.req,
130            None,
131        )
132    }
133
134    /// Schedule the request to the service, without waiting for the response.
135    pub fn send_after(self, delay: Duration) -> impl InvocationHandle
136    where
137        Req: Serialize + 'static,
138    {
139        self.ctx.send(
140            self.request_target,
141            self.idempotency_key,
142            self.headers,
143            self.req,
144            Some(delay),
145        )
146    }
147}
148
149pub trait InvocationHandle {
150    fn invocation_id(&self) -> impl Future<Output = Result<String, TerminalError>> + Send;
151    fn cancel(&self) -> impl Future<Output = Result<(), TerminalError>> + Send;
152}
153
154pub trait CallFuture:
155    DurableFuture<Output = Result<Self::Response, TerminalError>> + InvocationHandle
156{
157    type Response;
158}