1use crate::{
4 Worker, WorkerRunError,
5 activities::{ActivityContext, ActivityError, ActivityInfo},
6};
7use futures_util::future::{BoxFuture, LocalBoxFuture};
8#[cfg(feature = "experimental")]
9use std::sync::OnceLock;
10use std::{any::Any, collections::HashMap, sync::Arc};
11use temporalio_common::{
12 data_converters::{
13 GenericPayloadConverter, PayloadConversionError, SerializationContext, TemporalSerializable,
14 },
15 protos::{
16 coresdk::{
17 workflow_activation::WorkflowActivation,
18 workflow_completion::WorkflowActivationCompletion,
19 },
20 temporal::api::common::v1::Payload,
21 },
22};
23
24mod activity_execution_value {
25 use super::*;
26
27 pub trait Sealed {
28 fn to_activity_payload(
29 &self,
30 context: &SerializationContext<'_>,
31 ) -> Result<Payload, PayloadConversionError>;
32 }
33
34 impl<T> Sealed for T
35 where
36 T: Any + TemporalSerializable + Send + Sync,
37 {
38 fn to_activity_payload(
39 &self,
40 context: &SerializationContext<'_>,
41 ) -> Result<Payload, PayloadConversionError> {
42 context.converter.to_payload(context, self)
43 }
44 }
45}
46
47pub struct Next<'a, I, O> {
51 inner: Box<dyn FnOnce(I) -> O + Send + 'a>,
52}
53
54impl<'a, I, O> Next<'a, I, O> {
55 pub(crate) fn new(f: impl FnOnce(I) -> O + Send + 'a) -> Self {
56 Self { inner: Box::new(f) }
57 }
58
59 pub fn run(self, input: I) -> O {
61 (self.inner)(input)
62 }
63}
64
65#[cfg_attr(not(feature = "experimental"), allow(unreachable_pub))]
66mod worker_lifecycle {
67 use super::*;
68
69 #[async_trait::async_trait(?Send)]
74 pub trait WorkerInterceptor: Send + Sync {
75 fn run_worker<'a>(
77 &'a self,
78 input: RunWorkerInput<'a>,
79 next: Next<'a, RunWorkerInput<'a>, LocalBoxFuture<'a, Result<(), WorkerRunError>>>,
80 ) -> LocalBoxFuture<'a, Result<(), WorkerRunError>> {
81 next.run(input)
82 }
83
84 fn with_workflow_replay_worker<'a>(
86 &'a self,
87 input: WithWorkflowReplayWorkerInput<'a>,
88 next: Next<
89 'a,
90 WithWorkflowReplayWorkerInput<'a>,
91 LocalBoxFuture<'a, Result<(), WorkerRunError>>,
92 >,
93 ) -> LocalBoxFuture<'a, Result<(), WorkerRunError>> {
94 next.run(input)
95 }
96
97 async fn on_workflow_activation_completion(
100 &self,
101 _completion: &WorkflowActivationCompletion,
102 ) {
103 }
104 fn on_shutdown(&self, _sdk_worker: &Worker) {}
107 async fn on_workflow_activation(
109 &self,
110 _activation: &WorkflowActivation,
111 ) -> Result<(), anyhow::Error> {
112 Ok(())
113 }
114 }
115
116 #[derive(Debug)]
118 #[non_exhaustive]
119 pub struct RunWorkerInput<'a> {
120 pub worker: &'a mut Worker,
122 }
123
124 impl<'a> RunWorkerInput<'a> {
125 pub(crate) fn new(worker: &'a mut Worker) -> Self {
126 Self { worker }
127 }
128 }
129
130 #[derive(Debug)]
132 #[non_exhaustive]
133 pub struct WithWorkflowReplayWorkerInput<'a> {
134 pub worker: &'a mut Worker,
136 }
137
138 impl<'a> WithWorkflowReplayWorkerInput<'a> {
139 pub(crate) fn new(worker: &'a mut Worker) -> Self {
140 Self { worker }
141 }
142 }
143
144 pub(crate) fn call_run_worker<'a>(
145 interceptors: &'a [Arc<dyn WorkerInterceptor>],
146 input: RunWorkerInput<'a>,
147 terminal: Next<'a, RunWorkerInput<'a>, LocalBoxFuture<'a, Result<(), WorkerRunError>>>,
148 ) -> LocalBoxFuture<'a, Result<(), WorkerRunError>> {
149 if let Some((interceptor, remaining)) = interceptors.split_first() {
150 let next = Next::new(move |input| call_run_worker(remaining, input, terminal));
151 interceptor.run_worker(input, next)
152 } else {
153 terminal.run(input)
154 }
155 }
156
157 pub(crate) fn call_with_workflow_replay_worker<'a>(
158 interceptors: &'a [Arc<dyn WorkerInterceptor>],
159 input: WithWorkflowReplayWorkerInput<'a>,
160 terminal: Next<
161 'a,
162 WithWorkflowReplayWorkerInput<'a>,
163 LocalBoxFuture<'a, Result<(), WorkerRunError>>,
164 >,
165 ) -> LocalBoxFuture<'a, Result<(), WorkerRunError>> {
166 if let Some((interceptor, remaining)) = interceptors.split_first() {
167 let next = Next::new(move |input| {
168 call_with_workflow_replay_worker(remaining, input, terminal)
169 });
170 interceptor.with_workflow_replay_worker(input, next)
171 } else {
172 terminal.run(input)
173 }
174 }
175}
176
177#[cfg(not(feature = "experimental"))]
178pub(crate) use worker_lifecycle::{
179 RunWorkerInput, WithWorkflowReplayWorkerInput, WorkerInterceptor,
180};
181#[cfg(feature = "experimental")]
182pub use worker_lifecycle::{RunWorkerInput, WithWorkflowReplayWorkerInput, WorkerInterceptor};
183pub(crate) use worker_lifecycle::{call_run_worker, call_with_workflow_replay_worker};
184
185#[non_exhaustive]
187pub struct ExecuteActivityInput {
188 context: ActivityContext,
189 args: Box<dyn Any + Send + Sync>,
190}
191
192impl ExecuteActivityInput {
193 pub(crate) fn new(context: ActivityContext, args: Box<dyn Any + Send + Sync>) -> Self {
194 Self { context, args }
195 }
196
197 pub(crate) fn into_parts(self) -> (ActivityContext, Box<dyn Any + Send + Sync>) {
198 (self.context, self.args)
199 }
200
201 pub fn activity_info(&self) -> &ActivityInfo {
203 self.context.info()
204 }
205
206 pub fn headers(&self) -> &HashMap<String, Payload> {
208 self.context.headers()
209 }
210
211 pub fn headers_mut(&mut self) -> &mut HashMap<String, Payload> {
213 self.context.headers_mut()
214 }
215
216 pub fn args_ref<T: Any>(&self) -> Option<&T> {
218 self.args.downcast_ref()
219 }
220
221 pub fn args_mut<T: Any>(&mut self) -> Option<&mut T> {
223 self.args.downcast_mut()
224 }
225}
226
227pub trait ActivityExecutionValue:
229 Any + TemporalSerializable + Send + Sync + activity_execution_value::Sealed
230{
231 fn as_any(&self) -> &dyn Any;
233}
234
235impl<T> ActivityExecutionValue for T
236where
237 T: Any + TemporalSerializable + Send + Sync,
238{
239 fn as_any(&self) -> &dyn Any {
240 self
241 }
242}
243
244impl dyn ActivityExecutionValue {
245 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
247 self.as_any().downcast_ref()
248 }
249
250 pub(crate) fn serialize_payload(
251 &self,
252 context: &SerializationContext<'_>,
253 ) -> Result<Payload, PayloadConversionError> {
254 self.to_activity_payload(context)
255 }
256}
257
258pub type ExecuteActivityResult = Result<Box<dyn ActivityExecutionValue>, ActivityError>;
260
261pub type ExecuteActivityOutput<'a> = BoxFuture<'a, ExecuteActivityResult>;
263
264pub trait ActivityInboundInterceptor: Send + Sync + 'static {
268 fn execute_activity<'a>(
270 &'a self,
271 input: ExecuteActivityInput,
272 next: Next<'a, ExecuteActivityInput, ExecuteActivityOutput<'a>>,
273 ) -> ExecuteActivityOutput<'a> {
274 next.run(input)
275 }
276}
277
278#[cfg(feature = "experimental")]
280#[derive(Default)]
281pub struct ReturnWorkflowExitValueInterceptor {
282 result_value: Arc<OnceLock<Payload>>,
283}
284
285#[cfg(feature = "experimental")]
286impl ReturnWorkflowExitValueInterceptor {
287 pub fn result_handle(&self) -> Arc<OnceLock<Payload>> {
289 self.result_value.clone()
290 }
291}
292
293#[async_trait::async_trait(?Send)]
294#[cfg(feature = "experimental")]
295impl WorkerInterceptor for ReturnWorkflowExitValueInterceptor {
296 async fn on_workflow_activation_completion(&self, c: &WorkflowActivationCompletion) {
297 if let Some(v) = c.complete_workflow_execution_value() {
298 let _ = self.result_value.set(v.clone());
299 }
300 }
301}