21
21
//! let worker_config = WorkerConfigBuilder::default().build()?;
22
22
//! let core_worker = init_worker(worker_config, client);
23
23
//!
24
- //! let mut worker = Worker::new(Arc::new(core_worker), "task_queue", None );
24
+ //! let mut worker = Worker::new(Arc::new(core_worker), "task_queue");
25
25
//! worker.register_activity(
26
26
//! "echo_activity",
27
27
//! |echo_me: String| async move { Ok(echo_me) },
28
28
//! );
29
- //! // TODO: This should be different
30
- //! worker.run_until_done().await?;
29
+ //! worker.run().await?;
31
30
//! Ok(())
32
31
//! }
33
32
//! ```
36
35
extern crate tracing;
37
36
38
37
mod conversions;
38
+ pub mod interceptors;
39
39
mod payload_converter;
40
40
mod workflow_context;
41
41
mod workflow_future;
@@ -45,6 +45,7 @@ pub use workflow_context::{
45
45
Signal , SignalData , SignalWorkflowOptions , WfContext ,
46
46
} ;
47
47
48
+ use crate :: interceptors:: WorkerInterceptor ;
48
49
use crate :: workflow_context:: { ChildWfCommon , PendingChildWorkflow } ;
49
50
use anyhow:: { anyhow, bail} ;
50
51
use futures:: { future:: BoxFuture , stream:: FuturesUnordered , FutureExt , StreamExt } ;
@@ -106,12 +107,17 @@ pub fn sdk_client_options(url: impl Into<Url>) -> ServerGatewayOptionsBuilder {
106
107
/// A worker that can poll for and respond to workflow tasks by using [WorkflowFunction]s,
107
108
/// and activity tasks by using [ActivityFunction]s
108
109
pub struct Worker {
109
- worker : Arc < dyn CoreWorker > ,
110
- task_queue : String ,
110
+ common : CommonWorker ,
111
111
workflow_half : WorkflowHalf ,
112
112
activity_half : ActivityHalf ,
113
113
}
114
114
115
+ struct CommonWorker {
116
+ worker : Arc < dyn CoreWorker > ,
117
+ task_queue : String ,
118
+ worker_interceptor : Option < Box < dyn WorkerInterceptor > > ,
119
+ }
120
+
115
121
struct WorkflowHalf {
116
122
/// Maps run id to the driver
117
123
workflows : HashMap < String , UnboundedSender < WorkflowActivation > > ,
@@ -132,8 +138,11 @@ impl Worker {
132
138
/// Create a new rust worker
133
139
pub fn new ( worker : Arc < dyn CoreWorker > , task_queue : impl Into < String > ) -> Self {
134
140
Self {
135
- worker,
136
- task_queue : task_queue. into ( ) ,
141
+ common : CommonWorker {
142
+ worker,
143
+ task_queue : task_queue. into ( ) ,
144
+ worker_interceptor : None ,
145
+ } ,
137
146
workflow_half : WorkflowHalf {
138
147
workflows : Default :: default ( ) ,
139
148
workflow_fns : Default :: default ( ) ,
@@ -148,12 +157,19 @@ impl Worker {
148
157
149
158
/// Access the worker's server gateway client
150
159
pub fn server_gateway ( & self ) -> Arc < dyn ServerGatewayApis + Send + Sync > {
151
- self . worker . server_gateway ( )
160
+ self . common . worker . server_gateway ( )
152
161
}
153
162
154
163
/// Returns the task queue name this worker polls on
155
164
pub fn task_queue ( & self ) -> & str {
156
- & self . task_queue
165
+ & self . common . task_queue
166
+ }
167
+
168
+ /// Return a handle that can be used to initiate shutdown.
169
+ /// TODO: Doc better after shutdown changes
170
+ pub fn shutdown_handle ( & self ) -> impl Fn ( ) {
171
+ let w = self . common . worker . clone ( ) ;
172
+ move || w. initiate_shutdown ( )
157
173
}
158
174
159
175
/// Register a Workflow function to invoke when the Worker is asked to run a workflow of
@@ -188,22 +204,22 @@ impl Worker {
188
204
pub async fn run ( & mut self ) -> Result < ( ) , anyhow:: Error > {
189
205
let ( shutdown_tx, shutdown_rx) = watch:: channel ( false ) ;
190
206
let pollers = async move {
191
- let ( worker , task_q , wf_half, act_half) = self . split_apart ( ) ;
207
+ let ( common , wf_half, act_half) = self . split_apart ( ) ;
192
208
let ( completions_tx, mut completions_rx) = unbounded_channel ( ) ;
193
209
let ( wf_poll_res, act_poll_res) = tokio:: join!(
194
210
// Workflow polling loop
195
211
async {
196
212
loop {
197
- let activation = match worker. poll_workflow_activation( ) . await {
213
+ info!( "Polling" ) ;
214
+ let activation = match common. worker. poll_workflow_activation( ) . await {
198
215
Err ( PollWfError :: ShutDown ) => {
199
216
break Result :: <_, anyhow:: Error >:: Ok ( ( ) ) ;
200
217
}
201
218
o => o?,
202
219
} ;
203
220
wf_half
204
221
. workflow_activation_handler(
205
- worker. as_ref( ) ,
206
- task_q,
222
+ common,
207
223
& shutdown_rx,
208
224
& completions_tx,
209
225
& mut completions_rx,
@@ -219,11 +235,11 @@ impl Worker {
219
235
if !act_half. activity_fns. is_empty( ) {
220
236
loop {
221
237
tokio:: select! {
222
- activity = worker. poll_activity_task( ) => {
238
+ activity = common . worker. poll_activity_task( ) => {
223
239
if matches!( activity, Err ( PollActivityError :: ShutDown ) ) {
224
240
break ;
225
241
}
226
- act_half. activity_task_handler( worker. clone( ) ,
242
+ act_half. activity_task_handler( common . worker. clone( ) ,
227
243
activity?) ?;
228
244
} ,
229
245
_ = shutdown_rx. changed( ) => { break }
@@ -240,32 +256,31 @@ impl Worker {
240
256
} ;
241
257
242
258
let myself = pollers. await ?;
259
+ info ! ( "Polling loop exited" ) ;
260
+ let _ = shutdown_tx. send ( true ) ;
243
261
while let Some ( h) = myself. workflow_half . join_handles . next ( ) . await {
244
262
h??;
245
263
}
246
- myself. worker . shutdown ( ) . await ;
264
+ myself. common . worker . shutdown ( ) . await ;
247
265
myself. workflow_half . workflows . clear ( ) ;
248
266
Ok ( ( ) )
249
267
}
250
268
269
+ /// Set a [WorkerInterceptor]
270
+ pub fn set_worker_interceptor ( & mut self , interceptor : Box < dyn WorkerInterceptor > ) {
271
+ self . common . worker_interceptor = Some ( interceptor) ;
272
+ }
273
+
251
274
/// Turns this rust worker into a new worker with all the same workflows and activities
252
275
/// registered, but with a new underlying core worker. Can be used to swap the worker for
253
276
/// a replay worker, change task queues, etc.
254
277
pub fn with_new_core_worker ( & mut self , new_core_worker : Arc < dyn CoreWorker > ) {
255
- self . worker = new_core_worker;
278
+ self . common . worker = new_core_worker;
256
279
}
257
280
258
- fn split_apart (
259
- & mut self ,
260
- ) -> (
261
- Arc < dyn CoreWorker > ,
262
- & str ,
263
- & mut WorkflowHalf ,
264
- & mut ActivityHalf ,
265
- ) {
281
+ fn split_apart ( & mut self ) -> ( & mut CommonWorker , & mut WorkflowHalf , & mut ActivityHalf ) {
266
282
(
267
- self . worker . clone ( ) ,
268
- & self . task_queue ,
283
+ & mut self . common ,
269
284
& mut self . workflow_half ,
270
285
& mut self . activity_half ,
271
286
)
@@ -275,8 +290,7 @@ impl Worker {
275
290
impl WorkflowHalf {
276
291
async fn workflow_activation_handler (
277
292
& mut self ,
278
- worker : & dyn CoreWorker ,
279
- task_queue : & str ,
293
+ common : & CommonWorker ,
280
294
shutdown_rx : & Receiver < bool > ,
281
295
completions_tx : & UnboundedSender < WorkflowActivationCompletion > ,
282
296
completions_rx : & mut UnboundedReceiver < WorkflowActivationCompletion > ,
@@ -295,8 +309,8 @@ impl WorkflowHalf {
295
309
. ok_or_else ( || anyhow ! ( "Workflow type {workflow_type} not found" ) ) ?;
296
310
297
311
let ( wff, activations) = wf_function. start_workflow (
298
- worker. get_config ( ) . namespace . clone ( ) ,
299
- task_queue. to_string ( ) ,
312
+ common . worker . get_config ( ) . namespace . clone ( ) ,
313
+ common . task_queue . clone ( ) ,
300
314
// NOTE: Don't clone args if this gets ported to be a non-test rust worker
301
315
sw. arguments . clone ( ) ,
302
316
completions_tx. clone ( ) ,
@@ -323,10 +337,13 @@ impl WorkflowHalf {
323
337
} ;
324
338
325
339
let completion = completions_rx. recv ( ) . await . expect ( "No workflows left?" ) ;
326
- if completion . has_execution_ending ( ) {
327
- debug ! ( "Workflow {} says it's finishing" , & completion. run_id ) ;
340
+ if let Some ( ref i ) = common . worker_interceptor {
341
+ i . on_workflow_activation_completion ( & completion) ;
328
342
}
329
- worker. complete_workflow_activation ( completion) . await ?;
343
+ common
344
+ . worker
345
+ . complete_workflow_activation ( completion)
346
+ . await ?;
330
347
Ok ( ( ) )
331
348
}
332
349
}
0 commit comments