restate_sdk/lib.rs
1//! # Restate Rust SDK
2//!
3//! [Restate](https://restate.dev/) is a system for easily building resilient applications.
4//! This crate is the Restate SDK for writing Restate services using Rust.
5//!
6//! ## New to Restate?
7//!
8//! If you are new to Restate, we recommend the following resources:
9//!
10//! - [Learn about the concepts of Restate](https://docs.restate.dev/concepts/durable_building_blocks)
11//! - Use cases:
12//! - [Workflows](https://docs.restate.dev/use-cases/workflows)
13//! - [Microservice orchestration](https://docs.restate.dev/use-cases/microservice-orchestration)
14//! - [Event processing](https://docs.restate.dev/use-cases/event-processing)
15//! - [Async tasks](https://docs.restate.dev/use-cases/async-tasks)
16//! - [Quickstart](https://docs.restate.dev/get_started/quickstart?sdk=rust)
17//! - [Do the Tour of Restate to try out the APIs](https://docs.restate.dev/get_started/tour/?sdk=rust)
18//!
19//! # Features
20//!
21//! Have a look at the following SDK capabilities:
22//!
23//! - [SDK Overview](#sdk-overview): Overview of the SDK and how to implement services, virtual objects, and workflows.
24//! - [Service Communication][crate::context::ContextClient]: Durable RPC and messaging between services (optionally with a delay).
25//! - [Journaling Results][crate::context::ContextSideEffects]: Persist results in Restate's log to avoid re-execution on retries
26//! - State: [read][crate::context::ContextReadState] and [write](crate::context::ContextWriteState): Store and retrieve state in Restate's key-value store
27//! - [Scheduling & Timers][crate::context::ContextTimers]: Let a handler pause for a certain amount of time. Restate durably tracks the timer across failures.
28//! - [Awakeables][crate::context::ContextAwakeables]: Durable Futures to wait for events and the completion of external tasks.
29//! - [Error Handling][crate::errors]: Restate retries failures infinitely. Use `TerminalError` to stop retries.
30//! - [Serialization][crate::serde]: The SDK serializes results to send them to the Server. Includes [Schema Generation and payload metadata](crate::serde::PayloadMetadata) for documentation & discovery.
31//! - [Serving][crate::http_server]: Start an HTTP server to expose services.
32//!
33//! # SDK Overview
34//!
35//! The Restate Rust SDK lets you implement durable handlers. Handlers can be part of three types of services:
36//!
37//! - [Services](https://docs.restate.dev/concepts/services/#services-1): a collection of durable handlers
38//! - [Virtual Objects](https://docs.restate.dev/concepts/services/#virtual-objects): an object consists of a collection of durable handlers and isolated K/V state. Virtual Objects are useful for modeling stateful entities, where at most one handler can run at a time per object.
39//! - [Workflows](https://docs.restate.dev/concepts/services/#workflows): Workflows have a `run` handler that executes exactly once per workflow instance, and executes a set of steps durably. Workflows can have other handlers that can be called multiple times and interact with the workflow.
40//!
41//! ## Services
42//!
43//! [Services](https://docs.restate.dev/concepts/services/#services-1) and their handlers are defined as follows:
44//!
45//! ```rust,no_run
46//! // The prelude contains all the imports you need to get started
47//! use restate_sdk::prelude::*;
48//!
49//! // Define the service using Rust traits
50//! #[restate_sdk::service]
51//! trait MyService {
52//! async fn my_handler(greeting: String) -> Result<String, HandlerError>;
53//! }
54//!
55//! // Implement the service
56//! struct MyServiceImpl;
57//! impl MyService for MyServiceImpl {
58//!
59//! async fn my_handler(&self, ctx: Context<'_>, greeting: String) -> Result<String, HandlerError> {
60//! Ok(format!("{greeting}!"))
61//! }
62//!
63//! }
64//!
65//! // Start the HTTP server to expose services
66//! #[tokio::main]
67//! async fn main() {
68//! HttpServer::new(Endpoint::builder().bind(MyServiceImpl.serve()).build())
69//! .listen_and_serve("0.0.0.0:9080".parse().unwrap())
70//! .await;
71//! }
72//! ```
73//!
74//! - Specify that you want to create a service by using the [`#[restate_sdk::service]` macro](restate_sdk_macros::service).
75//! - Create a trait with the service handlers.
76//! - Handlers can accept zero or one parameter and return a [`Result`].
77//! - The type of the input parameter of the handler needs to implement [`Serialize`](crate::serde::Deserialize) and [`Deserialize`](crate::serde::Deserialize). See [`crate::serde`].
78//! - The Result contains the return value or a [`HandlerError`][crate::errors::HandlerError], which can be a [`TerminalError`](crate::errors::TerminalError) or any other Rust's [`std::error::Error`].
79//! - The service handler can now be called at `<RESTATE_INGRESS_URL>/MyService/myHandler`. You can optionally override the handler name used via `#[name = "myHandler"]`. More details on handler invocations can be found in the [docs](https://docs.restate.dev/invoke/http).
80//! - Implement the trait on a concrete type, for example on a struct.
81//! - The first parameter of a handler after `&self` is always a [`Context`](crate::context::Context) to interact with Restate.
82//! The SDK stores the actions you do on the context in the Restate journal to make them durable.
83//! - Finally, create an HTTP endpoint and bind the service(s) to it. Listen on the specified port (here 9080) for connections and requests.
84//!
85//! ## Virtual Objects
86//! [Virtual Objects](https://docs.restate.dev/concepts/services/#virtual-objects) and their handlers are defined similarly to services, with the following differences:
87//!
88//! ```rust,no_run
89//!use restate_sdk::prelude::*;
90//!
91//! #[restate_sdk::object]
92//! pub trait MyVirtualObject {
93//! async fn my_handler(name: String) -> Result<String, HandlerError>;
94//! #[shared]
95//! async fn my_concurrent_handler(name: String) -> Result<String, HandlerError>;
96//! }
97//!
98//! pub struct MyVirtualObjectImpl;
99//!
100//! impl MyVirtualObject for MyVirtualObjectImpl {
101//!
102//! async fn my_handler(
103//! &self,
104//! ctx: ObjectContext<'_>,
105//! greeting: String,
106//! ) -> Result<String, HandlerError> {
107//! Ok(format!("{} {}", greeting, ctx.key()))
108//! }
109//!
110//! async fn my_concurrent_handler(
111//! &self,
112//! ctx: SharedObjectContext<'_>,
113//! greeting: String,
114//! ) -> Result<String, HandlerError> {
115//! Ok(format!("{} {}", greeting, ctx.key()))
116//! }
117//!
118//! }
119//!
120//! #[tokio::main]
121//! async fn main() {
122//! HttpServer::new(
123//! Endpoint::builder()
124//! .bind(MyVirtualObjectImpl.serve())
125//! .build(),
126//! )
127//! .listen_and_serve("0.0.0.0:9080".parse().unwrap())
128//! .await;
129//! }
130//! ```
131//!
132//! - Specify that you want to create a Virtual Object by using the [`#[restate_sdk::object]` macro](restate_sdk_macros::object).
133//! - The first argument of each handler must be the [`ObjectContext`](crate::context::ObjectContext) parameter. Handlers with the `ObjectContext` parameter can write to the K/V state store. Only one handler can be active at a time per object, to ensure consistency.
134//! - You can retrieve the key of the object you are in via [`ObjectContext.key`].
135//! - If you want to have a handler that executes concurrently to the others and doesn't have write access to the K/V state, add `#[shared]` to the handler definition in the trait.
136//! Shared handlers need to use the [`SharedObjectContext`](crate::context::SharedObjectContext).
137//! You can use these handlers, for example, to read K/V state and expose it to the outside world, or to interact with the blocking handler and resolve awakeables etc.
138//!
139//! ## Workflows
140//!
141//! [Workflows](https://docs.restate.dev/concepts/services/#workflows) are a special type of Virtual Objects, their definition is similar but with the following differences:
142//!
143//! ```rust,no_run
144//! use restate_sdk::prelude::*;
145//!
146//! #[restate_sdk::workflow]
147//! pub trait MyWorkflow {
148//! async fn run(req: String) -> Result<String, HandlerError>;
149//! #[shared]
150//! async fn interact_with_workflow() -> Result<(), HandlerError>;
151//! }
152//!
153//! pub struct MyWorkflowImpl;
154//!
155//! impl MyWorkflow for MyWorkflowImpl {
156//!
157//! async fn run(&self, ctx: WorkflowContext<'_>, req: String) -> Result<String, HandlerError> {
158//! //! implement workflow logic here
159//!
160//! Ok(String::from("success"))
161//! }
162//!
163//! async fn interact_with_workflow(&self, ctx: SharedWorkflowContext<'_>) -> Result<(), HandlerError> {
164//! //! implement interaction logic here
165//! //! e.g. resolve a promise that the workflow is waiting on
166//!
167//! Ok(())
168//! }
169//!
170//! }
171//!
172//! #[tokio::main]
173//! async fn main() {
174//! HttpServer::new(Endpoint::builder().bind(MyWorkflowImpl.serve()).build())
175//! .listen_and_serve("0.0.0.0:9080".parse().unwrap())
176//! .await;
177//! }
178//! ```
179//!
180//! - Specify that you want to create a Workflow by using the [`#[restate_sdk::workflow]` macro](workflow).
181//! - The workflow needs to have a `run` handler.
182//! - The first argument of the `run` handler must be the [`WorkflowContext`](crate::context::WorkflowContext) parameter.
183//! The `WorkflowContext` parameter is used to interact with Restate.
184//! The `run` handler executes exactly once per workflow instance.
185//! - The other handlers of the workflow are used to interact with the workflow: either query it, or signal it.
186//! They use the [`SharedWorkflowContext`](crate::context::SharedWorkflowContext) to interact with the SDK.
187//! These handlers can run concurrently with the run handler and can still be called after the run handler has finished.
188//! - Have a look at the [workflow docs](workflow) to learn more.
189//!
190//!
191//! Learn more about each service type here:
192//! - [Service](restate_sdk_macros::service)
193//! - [Virtual Object](object)
194//! - [Workflow](workflow)
195//!
196//!
197//! ### Logging
198//!
199//! This crate uses the [tracing crate][tracing] to emit logs, so you'll need to configure a tracing subscriber to get logs. For example, to configure console logging using `tracing_subscriber::fmt`:
200//! ```rust,no_run
201//! #[tokio::main]
202//! async fn main() {
203//! //! To enable logging
204//! tracing_subscriber::fmt::init();
205//!
206//! // Start http server etc...
207//! }
208//! ```
209//!
210//! You can filter logs *when a handler is being replayed* configuring the [filter::ReplayAwareFilter].
211//!
212//! For more information about tracing and logging, have a look at the [tracing subscriber doc](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables).
213//!
214//! Next, have a look at the other [SDK features](#features).
215//!
216
217pub mod endpoint;
218pub mod service;
219
220pub mod context;
221pub mod discovery;
222pub mod errors;
223#[cfg(feature = "tracing-span-filter")]
224pub mod filter;
225#[cfg(feature = "http_server")]
226pub mod http_server;
227#[cfg(feature = "hyper")]
228pub mod hyper;
229pub mod serde;
230
231/// Entry-point macro to define a Restate [Service](https://docs.restate.dev/concepts/services#services-1).
232///
233/// ```rust,no_run
234/// use restate_sdk::prelude::*;
235///
236/// #[restate_sdk::service]
237/// trait Greeter {
238/// async fn greet(name: String) -> Result<String, HandlerError>;
239/// }
240/// ```
241///
242/// This macro accepts a `trait` as input, and generates as output:
243///
244/// * A trait with the same name, that you should implement on your own concrete type (e.g. `struct`), e.g.:
245///
246/// ```rust,no_run
247/// # use restate_sdk::prelude::*;
248/// # #[restate_sdk::service]
249/// # trait Greeter {
250/// # async fn greet(name: String) -> Result<String, HandlerError>;
251/// # }
252/// struct GreeterImpl;
253/// impl Greeter for GreeterImpl {
254/// async fn greet(&self, _: Context<'_>, name: String) -> Result<String, HandlerError> {
255/// Ok(format!("Greetings {name}"))
256/// }
257/// }
258/// ```
259///
260/// This trait will additionally contain, for each handler, the appropriate [`Context`](crate::prelude::Context), to interact with Restate.
261///
262/// * An implementation of the [`Service`](crate::service::Service) trait, to bind the service in the [`Endpoint`](crate::prelude::Endpoint) and expose it:
263///
264/// ```rust,no_run
265/// # use restate_sdk::prelude::*;
266/// # #[restate_sdk::service]
267/// # trait Greeter {
268/// # async fn greet(name: String) -> HandlerResult<String>;
269/// # }
270/// # struct GreeterImpl;
271/// # impl Greeter for GreeterImpl {
272/// # async fn greet(&self, _: Context<'_>, name: String) -> HandlerResult<String> {
273/// # Ok(format!("Greetings {name}"))
274/// # }
275/// # }
276/// let endpoint = Endpoint::builder()
277/// // .serve() returns the implementation of Service used by the SDK
278/// // to bind your struct to the endpoint
279/// .bind(GreeterImpl.serve())
280/// .build();
281/// ```
282///
283/// * A client implementation to call this service from another service, object or workflow, e.g.:
284///
285/// ```rust,no_run
286/// # use restate_sdk::prelude::*;
287/// # #[restate_sdk::service]
288/// # trait Greeter {
289/// # async fn greet(name: String) -> HandlerResult<String>;
290/// # }
291/// # async fn example(ctx: Context<'_>) -> Result<(), TerminalError> {
292/// let result = ctx
293/// .service_client::<GreeterClient>()
294/// .greet("My greetings".to_string())
295/// .call()
296/// .await?;
297/// # Ok(())
298/// # }
299/// ```
300///
301/// Methods of this trait can accept either no parameter, or one parameter implementing [`Deserialize`](crate::serde::Deserialize).
302/// The return value MUST always be a `Result`. Down the hood, the error type is always converted to [`HandlerError`](crate::prelude::HandlerError) for the SDK to distinguish between terminal and retryable errors. For more details, check the [`HandlerError`](crate::prelude::HandlerError) doc.
303///
304/// When invoking the service through Restate, the method name should be used as handler name, that is:
305///
306/// ```rust,no_run
307/// use restate_sdk::prelude::*;
308///
309/// #[restate_sdk::service]
310/// trait Greeter {
311/// async fn my_greet(name: String) -> Result<String, HandlerError>;
312/// }
313/// ```
314///
315/// The `Greeter/my_greet` handler be invoked sending a request to `http://<RESTATE_ENDPOINT>/Greeter/my_greet`.
316/// You can override the names used by Restate during registration using the `name` attribute:
317///
318/// ```rust,no_run
319/// use restate_sdk::prelude::*;
320///
321/// #[restate_sdk::service]
322/// #[name = "greeter"]
323/// trait Greeter {
324/// // You can invoke this handler with `http://<RESTATE_ENDPOINT>/greeter/myGreet`
325/// #[name = "myGreet"]
326/// async fn my_greet(name: String) -> Result<String, HandlerError>;
327/// }
328/// ```
329pub use restate_sdk_macros::service;
330
331/// Entry-point macro to define a Restate [Virtual object](https://docs.restate.dev/concepts/services#virtual-objects).
332///
333/// For more details, check the [`service` macro](macro@crate::service) documentation.
334///
335/// ## Shared handlers
336///
337/// To define a shared handler, simply annotate the handler with the `#[shared]` annotation:
338///
339/// ```rust,no_run
340/// use restate_sdk::prelude::*;
341///
342/// #[restate_sdk::object]
343/// trait Counter {
344/// async fn add(val: u64) -> Result<u64, TerminalError>;
345/// #[shared]
346/// async fn get() -> Result<u64, TerminalError>;
347/// }
348/// ```
349pub use restate_sdk_macros::object;
350
351///
352/// # Workflows
353///
354/// Entry-point macro to define a Restate [Workflow](https://docs.restate.dev/concepts/services#workflows).
355///
356/// [Workflows](https://docs.restate.dev/concepts/services#workflows) are a sequence of steps that gets executed durably.
357///
358/// A workflow can be seen as a special type of [Virtual Object](https://docs.restate.dev/concepts/services#virtual-objects) with the following characteristics:
359///
360/// - Each workflow definition has a **`run` handler** that implements the workflow logic.
361/// - The `run` handler **executes exactly one time** for each workflow instance (object / key).
362/// - The `run` handler executes a set of **durable steps/activities**. These can either be:
363/// - Inline activities: for example a [run block](crate::context::ContextSideEffects) or [sleep](crate::context::ContextTimers)
364/// - [Calls to other handlers](crate::context::ContextClient) implementing the activities
365/// - You can **submit a workflow** in the same way as any handler invocation (via SDK clients or Restate services, over HTTP or Kafka).
366/// - A workflow definition can implement other handlers that can be called multiple times, and can **interact with the workflow**:
367/// - Query the workflow (get information out of it) by getting K/V state or awaiting promises that are resolved by the workflow.
368/// - Signal the workflow (send information to it) by resolving promises that the workflow waits on.
369/// - Workflows have access to the [`WorkflowContext`](crate::context::WorkflowContext) and [`SharedWorkflowContext`](crate::context::SharedWorkflowContext), giving them some extra functionality, for example [Durable Promises](#signaling-workflows) to signal workflows.
370/// - The K/V state of the workflow is isolated to the workflow execution, and can only be mutated by the `run` handler.
371///
372/// **Note: Workflow retention time**:
373/// The retention time of a workflow execution is 24 hours after the finishing of the `run` handler.
374/// After this timeout any [K/V state][crate::context::ContextReadState] is cleared, the workflow's shared handlers cannot be called anymore, and the Durable Promises are discarded.
375/// The retention time can be configured via the [Admin API](https://docs.restate.dev/references/admin-api/#tag/service/operation/modify_service) per Workflow definition by setting `workflow_completion_retention`.
376///
377/// ## Implementing workflows
378/// Have a look at the code example to get a better understanding of how workflows are implemented:
379///
380/// ```rust,no_run
381/// use restate_sdk::prelude::*;
382///
383/// #[restate_sdk::workflow]
384/// pub trait SignupWorkflow {
385/// async fn run(req: String) -> Result<bool, HandlerError>;
386/// #[shared]
387/// async fn click(click_secret: String) -> Result<(), HandlerError>;
388/// #[shared]
389/// async fn get_status() -> Result<String, HandlerError>;
390/// }
391///
392/// pub struct SignupWorkflowImpl;
393///
394/// impl SignupWorkflow for SignupWorkflowImpl {
395///
396/// async fn run(&self, mut ctx: WorkflowContext<'_>, email: String) -> Result<bool, HandlerError> {
397/// let secret = ctx.rand_uuid().to_string();
398/// ctx.run(|| send_email_with_link(email.clone(), secret.clone())).await?;
399/// ctx.set("status", "Email sent".to_string());
400///
401/// let click_secret = ctx.promise::<String>("email.clicked").await?;
402/// ctx.set("status", "Email clicked".to_string());
403///
404/// Ok(click_secret == secret)
405/// }
406///
407/// async fn click(&self, ctx: SharedWorkflowContext<'_>, click_secret: String) -> Result<(), HandlerError> {
408/// ctx.resolve_promise::<String>("email.clicked", click_secret);
409/// Ok(())
410/// }
411///
412/// async fn get_status(&self, ctx: SharedWorkflowContext<'_>) -> Result<String, HandlerError> {
413/// Ok(ctx.get("status").await?.unwrap_or("unknown".to_string()))
414/// }
415///
416/// }
417/// # async fn send_email_with_link(email: String, secret: String) -> Result<(), HandlerError> {
418/// # Ok(())
419/// # }
420///
421/// #[tokio::main]
422/// async fn main() {
423/// HttpServer::new(Endpoint::builder().bind(SignupWorkflowImpl.serve()).build())
424/// .listen_and_serve("0.0.0.0:9080".parse().unwrap())
425/// .await;
426/// }
427/// ```
428///
429/// ### The run handler
430///
431/// Every workflow needs a `run` handler.
432/// This handler has access to the same SDK features as Service and Virtual Object handlers.
433/// In the example above, we use [`ctx.run`][crate::context::ContextSideEffects::run] to log the sending of the email in Restate and avoid re-execution on replay.
434/// Or call other handlers to execute activities.
435///
436/// ## Shared handlers
437///
438/// To define a shared handler, simply annotate the handler with the `#[shared]` annotation:
439///
440/// ### Querying workflows
441///
442/// Similar to Virtual Objects, you can retrieve the [K/V state][crate::context::ContextReadState] of workflows via the other handlers defined in the workflow definition,
443/// In the example we expose the status of the workflow to external clients.
444/// Every workflow execution can be seen as a new object, so the state is isolated to a single workflow execution.
445/// The state can only be mutated by the `run` handler of the workflow. The other handlers can only read the state.
446///
447/// ### Signaling workflows
448///
449/// You can use Durable Promises to interact with your running workflows: to let the workflow block until an event occurs, or to send a signal / information into or out of a running workflow.
450/// These promises are durable and distributed, meaning they survive crashes and can be resolved or rejected by any handler in the workflow.
451///
452/// Do the following:
453/// 1. Create a promise that is durable and distributed in the `run` handler, and wait for its completion. In the example, we wait on the promise `email.clicked`.
454/// 2. Resolve or reject the promise in another handler in the workflow. This can be done at most one time.
455/// In the example, the `click` handler gets called when the user clicks a link in an email and resolves the `email.clicked` promise.
456///
457/// You can also use this pattern in reverse and let the `run` handler resolve promises that other handlers are waiting on.
458/// For example, the `run` handler could resolve a promise when it finishes a step of the workflow, so that other handlers can request whether this step has been completed.
459///
460/// ### Serving and registering workflows
461///
462/// You serve workflows in the same way as Services and Virtual Objects. Have a look at the [Serving docs][crate::http_server].
463/// Make sure you [register the endpoint or Lambda handler](https://docs.restate.dev/operate/registration) in Restate before invoking it.
464///
465/// **Tip: Workflows-as-code with Restate**:
466/// [Check out some examples of workflows-as-code with Restate on the use case page](https://docs.restate.dev/use-cases/workflows).
467///
468///
469/// ## Submitting workflows from a Restate service
470/// [**Submit/query/signal**][crate::context::ContextClient]:
471/// Call the workflow handlers in the same way as for Services and Virtual Objects.
472/// You can only call the `run` handler (submit) once per workflow ID (here `"someone"`).
473/// Check out the [Service Communication docs][crate::context::ContextClient] for more information.
474///
475/// ## Submitting workflows over HTTP
476/// [**Submit/query/signal**](https://docs.restate.dev/invoke/http#request-response-calls-over-http):
477/// Call any handler of the workflow in the same way as for Services and Virtual Objects.
478/// This returns the result of the handler once it has finished.
479/// Add `/send` to the path for one-way calls.
480/// You can only call the `run` handler once per workflow ID (here `"someone"`).
481///
482/// ```shell
483/// curl localhost:8080/SignupWorkflow/someone/run \
484/// -H 'content-type: application/json' \
485/// -d '"someone@restate.dev"'
486/// ```
487///
488/// [**Attach/peek**](https://docs.restate.dev/invoke/http#retrieve-result-of-invocations-and-workflows):
489/// This lets you retrieve the result of a workflow or check if it's finished.
490///
491/// ```shell
492/// curl localhost:8080/restate/workflow/SignupWorkflow/someone/attach
493/// curl localhost:8080/restate/workflow/SignupWorkflow/someone/output
494/// ```
495///
496/// ## Inspecting workflows
497///
498/// Have a look at the [introspection docs](https://docs.restate.dev/operate/introspection) on how to inspect workflows.
499/// You can use this to for example:
500/// - [Inspect the progress of a workflow by looking at the invocation journal](https://docs.restate.dev/operate/introspection#inspecting-the-invocation-journal)
501/// - [Inspect the K/V state of a workflow](https://docs.restate.dev/operate/introspection#inspecting-application-state)
502///
503///
504/// For more details, check the [`service` macro](macro@crate::service) documentation.
505pub use restate_sdk_macros::workflow;
506
507/// Prelude contains all the useful imports you need to get started with Restate.
508pub mod prelude {
509 #[cfg(feature = "http_server")]
510 pub use crate::http_server::HttpServer;
511
512 pub use crate::context::{
513 CallFuture, Context, ContextAwakeables, ContextClient, ContextPromises, ContextReadState,
514 ContextSideEffects, ContextTimers, ContextWriteState, HeaderMap, InvocationHandle,
515 ObjectContext, Request, RunFuture, RunRetryPolicy, SharedObjectContext,
516 SharedWorkflowContext, WorkflowContext,
517 };
518 pub use crate::endpoint::{Endpoint, HandlerOptions, ServiceOptions};
519 pub use crate::errors::{HandlerError, HandlerResult, TerminalError};
520 pub use crate::serde::Json;
521}