@temporalio/core-bridge 0.20.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +137 -127
- package/index.d.ts +7 -2
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/docker-compose.yaml +5 -4
- package/sdk-core/client/Cargo.toml +1 -0
- package/sdk-core/client/src/lib.rs +52 -9
- package/sdk-core/client/src/raw.rs +9 -1
- package/sdk-core/client/src/retry.rs +12 -1
- package/sdk-core/client/src/workflow_handle/mod.rs +183 -0
- package/sdk-core/core/src/abstractions.rs +10 -3
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -9
- package/sdk-core/core/src/core_tests/determinism.rs +8 -19
- package/sdk-core/core/src/core_tests/local_activities.rs +22 -32
- package/sdk-core/core/src/core_tests/queries.rs +272 -5
- package/sdk-core/core/src/core_tests/workers.rs +4 -34
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +197 -41
- package/sdk-core/core/src/pending_activations.rs +11 -0
- package/sdk-core/core/src/telemetry/mod.rs +1 -1
- package/sdk-core/core/src/test_help/mod.rs +57 -7
- package/sdk-core/core/src/worker/mod.rs +64 -15
- package/sdk-core/core/src/workflow/machines/mod.rs +1 -1
- package/sdk-core/core/src/workflow/machines/timer_state_machine.rs +2 -2
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +14 -3
- package/sdk-core/core/src/workflow/mod.rs +5 -2
- package/sdk-core/core/src/workflow/workflow_tasks/cache_manager.rs +47 -2
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +16 -2
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +252 -125
- package/sdk-core/core-api/src/worker.rs +9 -0
- package/sdk-core/sdk/Cargo.toml +1 -0
- package/sdk-core/sdk/src/activity_context.rs +223 -0
- package/sdk-core/sdk/src/interceptors.rs +8 -2
- package/sdk-core/sdk/src/lib.rs +167 -122
- package/sdk-core/sdk-core-protos/src/history_info.rs +3 -7
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/test-utils/src/lib.rs +78 -37
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +11 -4
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +0 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +0 -3
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +33 -17
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +10 -1
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +0 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +71 -3
- package/sdk-core/tests/load_tests.rs +80 -6
- package/src/errors.rs +9 -2
- package/src/lib.rs +39 -16
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
package/sdk-core/sdk/src/lib.rs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
//! An example of running an activity worker:
|
|
10
10
|
//! ```no_run
|
|
11
11
|
//! use std::{sync::Arc, str::FromStr};
|
|
12
|
-
//! use temporal_sdk::{sdk_client_options, Worker};
|
|
12
|
+
//! use temporal_sdk::{sdk_client_options, Worker, ActContext};
|
|
13
13
|
//! use temporal_sdk_core::{init_worker, Url};
|
|
14
14
|
//! use temporal_sdk_core_api::worker::{WorkerConfig, WorkerConfigBuilder};
|
|
15
15
|
//!
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
//! let mut worker = Worker::new_from_core(Arc::new(core_worker), "task_queue");
|
|
24
24
|
//! worker.register_activity(
|
|
25
25
|
//! "echo_activity",
|
|
26
|
-
//! |echo_me: String| async move { Ok(echo_me) },
|
|
26
|
+
//! |_ctx: ActContext, echo_me: String| async move { Ok(echo_me) },
|
|
27
27
|
//! );
|
|
28
28
|
//! worker.run().await?;
|
|
29
29
|
//! Ok(())
|
|
@@ -33,12 +33,15 @@
|
|
|
33
33
|
#[macro_use]
|
|
34
34
|
extern crate tracing;
|
|
35
35
|
|
|
36
|
+
mod activity_context;
|
|
36
37
|
mod conversions;
|
|
37
38
|
pub mod interceptors;
|
|
38
39
|
mod payload_converter;
|
|
39
40
|
mod workflow_context;
|
|
40
41
|
mod workflow_future;
|
|
41
42
|
|
|
43
|
+
pub use activity_context::ActContext;
|
|
44
|
+
|
|
42
45
|
pub use workflow_context::{
|
|
43
46
|
ActivityOptions, CancellableFuture, ChildWorkflow, ChildWorkflowOptions, LocalActivityOptions,
|
|
44
47
|
Signal, SignalData, SignalWorkflowOptions, WfContext,
|
|
@@ -49,9 +52,10 @@ use crate::{
|
|
|
49
52
|
workflow_context::{ChildWfCommon, PendingChildWorkflow},
|
|
50
53
|
};
|
|
51
54
|
use anyhow::{anyhow, bail};
|
|
52
|
-
use futures::{future::BoxFuture,
|
|
55
|
+
use futures::{future::BoxFuture, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
|
53
56
|
use once_cell::sync::OnceCell;
|
|
54
57
|
use std::{
|
|
58
|
+
cell::RefCell,
|
|
55
59
|
collections::HashMap,
|
|
56
60
|
fmt::{Debug, Display, Formatter},
|
|
57
61
|
future::Future,
|
|
@@ -82,12 +86,12 @@ use temporal_sdk_core_protos::{
|
|
|
82
86
|
};
|
|
83
87
|
use tokio::{
|
|
84
88
|
sync::{
|
|
85
|
-
mpsc::{unbounded_channel,
|
|
86
|
-
oneshot,
|
|
87
|
-
watch::Receiver,
|
|
89
|
+
mpsc::{unbounded_channel, UnboundedSender},
|
|
90
|
+
oneshot,
|
|
88
91
|
},
|
|
89
92
|
task::JoinError,
|
|
90
93
|
};
|
|
94
|
+
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
91
95
|
use tokio_util::sync::CancellationToken;
|
|
92
96
|
|
|
93
97
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
@@ -120,13 +124,19 @@ struct CommonWorker {
|
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
struct WorkflowHalf {
|
|
123
|
-
/// Maps run id to
|
|
124
|
-
workflows: HashMap<String,
|
|
127
|
+
/// Maps run id to cached workflow state
|
|
128
|
+
workflows: RefCell<HashMap<String, WorkflowData>>,
|
|
125
129
|
/// Maps workflow type to the function for executing workflow runs with that ID
|
|
126
|
-
workflow_fns: HashMap<String, WorkflowFunction
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
workflow_fns: RefCell<HashMap<String, WorkflowFunction>>,
|
|
131
|
+
}
|
|
132
|
+
struct WorkflowData {
|
|
133
|
+
/// Channel used to send the workflow activations
|
|
134
|
+
activation_chan: UnboundedSender<WorkflowActivation>,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
struct WorkflowFutureHandle<F: Future<Output = Result<WorkflowResult<()>, JoinError>>> {
|
|
138
|
+
join_handle: F,
|
|
139
|
+
run_id: String,
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
struct ActivityHalf {
|
|
@@ -136,8 +146,6 @@ struct ActivityHalf {
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
impl Worker {
|
|
139
|
-
// pub fn new(cfg: WorkerConfig) -> Self {}
|
|
140
|
-
|
|
141
149
|
#[doc(hidden)]
|
|
142
150
|
/// Create a new rust worker from a core worker
|
|
143
151
|
pub fn new_from_core(worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
|
|
@@ -150,7 +158,6 @@ impl Worker {
|
|
|
150
158
|
workflow_half: WorkflowHalf {
|
|
151
159
|
workflows: Default::default(),
|
|
152
160
|
workflow_fns: Default::default(),
|
|
153
|
-
join_handles: FuturesUnordered::new(),
|
|
154
161
|
},
|
|
155
162
|
activity_half: ActivityHalf {
|
|
156
163
|
activity_fns: Default::default(),
|
|
@@ -180,6 +187,7 @@ impl Worker {
|
|
|
180
187
|
) {
|
|
181
188
|
self.workflow_half
|
|
182
189
|
.workflow_fns
|
|
190
|
+
.get_mut()
|
|
183
191
|
.insert(workflow_type.into(), wf_function.into());
|
|
184
192
|
}
|
|
185
193
|
|
|
@@ -201,67 +209,103 @@ impl Worker {
|
|
|
201
209
|
/// Runs the worker. Eventually resolves after the worker has been explicitly shut down,
|
|
202
210
|
/// or may return early with an error in the event of some unresolvable problem.
|
|
203
211
|
pub async fn run(&mut self) -> Result<(), anyhow::Error> {
|
|
204
|
-
let
|
|
205
|
-
let
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
212
|
+
let shutdown_token = CancellationToken::new();
|
|
213
|
+
let (common, wf_half, act_half) = self.split_apart();
|
|
214
|
+
let (wf_future_tx, wf_future_rx) = unbounded_channel();
|
|
215
|
+
let (completions_tx, completions_rx) = unbounded_channel();
|
|
216
|
+
let wf_future_joiner = async {
|
|
217
|
+
UnboundedReceiverStream::new(wf_future_rx)
|
|
218
|
+
.map(Result::<_, anyhow::Error>::Ok)
|
|
219
|
+
.try_for_each_concurrent(
|
|
220
|
+
None,
|
|
221
|
+
|WorkflowFutureHandle {
|
|
222
|
+
join_handle,
|
|
223
|
+
run_id,
|
|
224
|
+
}| {
|
|
225
|
+
let wf_half = &*wf_half;
|
|
226
|
+
async move {
|
|
227
|
+
join_handle.await??;
|
|
228
|
+
wf_half.workflows.borrow_mut().remove(&run_id);
|
|
229
|
+
Ok(())
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
)
|
|
233
|
+
.await
|
|
234
|
+
};
|
|
235
|
+
let wf_completion_processor = async {
|
|
236
|
+
let r = UnboundedReceiverStream::new(completions_rx)
|
|
237
|
+
.map(Ok)
|
|
238
|
+
.try_for_each_concurrent(None, |completion| async {
|
|
239
|
+
if let Some(ref i) = common.worker_interceptor {
|
|
240
|
+
i.on_workflow_activation_completion(&completion).await;
|
|
228
241
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
activity?)?;
|
|
243
|
-
},
|
|
244
|
-
_ = shutdown_rx.changed() => { break }
|
|
245
|
-
}
|
|
242
|
+
common.worker.complete_workflow_activation(completion).await
|
|
243
|
+
})
|
|
244
|
+
.map_err(Into::into)
|
|
245
|
+
.await;
|
|
246
|
+
r
|
|
247
|
+
};
|
|
248
|
+
tokio::try_join!(
|
|
249
|
+
// Workflow polling loop
|
|
250
|
+
async {
|
|
251
|
+
loop {
|
|
252
|
+
let activation = match common.worker.poll_workflow_activation().await {
|
|
253
|
+
Err(PollWfError::ShutDown) => {
|
|
254
|
+
break;
|
|
246
255
|
}
|
|
256
|
+
o => o?,
|
|
247
257
|
};
|
|
248
|
-
|
|
258
|
+
if let Some(wf_fut) = wf_half.workflow_activation_handler(
|
|
259
|
+
common,
|
|
260
|
+
shutdown_token.clone(),
|
|
261
|
+
activation,
|
|
262
|
+
&completions_tx,
|
|
263
|
+
)? {
|
|
264
|
+
if wf_future_tx.send(wf_fut).is_err() {
|
|
265
|
+
panic!(
|
|
266
|
+
"Receive half of completion processor channel cannot be dropped"
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
249
270
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
271
|
+
// Tell still-alive workflows to evict themselves
|
|
272
|
+
shutdown_token.cancel();
|
|
273
|
+
// It's important to drop these so the future and completion processors will
|
|
274
|
+
// terminate.
|
|
275
|
+
drop(wf_future_tx);
|
|
276
|
+
drop(completions_tx);
|
|
277
|
+
Result::<_, anyhow::Error>::Ok(())
|
|
278
|
+
},
|
|
279
|
+
// Only poll on the activity queue if activity functions have been registered. This
|
|
280
|
+
// makes tests which use mocks dramatically more manageable.
|
|
281
|
+
async {
|
|
282
|
+
if !act_half.activity_fns.is_empty() {
|
|
283
|
+
let shutdown_token = shutdown_token.clone();
|
|
284
|
+
loop {
|
|
285
|
+
tokio::select! {
|
|
286
|
+
activity = common.worker.poll_activity_task() => {
|
|
287
|
+
if matches!(activity, Err(PollActivityError::ShutDown)) {
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
act_half.activity_task_handler(common.worker.clone(),
|
|
291
|
+
common.task_queue.clone(),
|
|
292
|
+
activity?)?;
|
|
293
|
+
},
|
|
294
|
+
_ = shutdown_token.cancelled() => { break }
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
Result::<_, anyhow::Error>::Ok(())
|
|
299
|
+
},
|
|
300
|
+
wf_future_joiner,
|
|
301
|
+
wf_completion_processor,
|
|
302
|
+
)?;
|
|
256
303
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
while let Some(h) = myself.workflow_half.join_handles.next().await {
|
|
261
|
-
h??;
|
|
304
|
+
info!("Polling loops exited");
|
|
305
|
+
if let Some(i) = self.common.worker_interceptor.as_ref() {
|
|
306
|
+
i.on_shutdown(self);
|
|
262
307
|
}
|
|
263
|
-
|
|
264
|
-
myself.workflow_half.workflows.clear();
|
|
308
|
+
self.common.worker.shutdown().await;
|
|
265
309
|
Ok(())
|
|
266
310
|
}
|
|
267
311
|
|
|
@@ -277,6 +321,12 @@ impl Worker {
|
|
|
277
321
|
self.common.worker = new_core_worker;
|
|
278
322
|
}
|
|
279
323
|
|
|
324
|
+
/// Returns number of currently cached workflows as understood by the SDK. Importantly, this
|
|
325
|
+
/// is not the same as understood by core, though they *should* always be in sync.
|
|
326
|
+
pub fn cached_workflows(&self) -> usize {
|
|
327
|
+
self.workflow_half.workflows.borrow().len()
|
|
328
|
+
}
|
|
329
|
+
|
|
280
330
|
fn split_apart(&mut self) -> (&mut CommonWorker, &mut WorkflowHalf, &mut ActivityHalf) {
|
|
281
331
|
(
|
|
282
332
|
&mut self.common,
|
|
@@ -287,14 +337,19 @@ impl Worker {
|
|
|
287
337
|
}
|
|
288
338
|
|
|
289
339
|
impl WorkflowHalf {
|
|
290
|
-
|
|
291
|
-
&
|
|
340
|
+
fn workflow_activation_handler(
|
|
341
|
+
&self,
|
|
292
342
|
common: &CommonWorker,
|
|
293
|
-
|
|
294
|
-
completions_tx: &UnboundedSender<WorkflowActivationCompletion>,
|
|
295
|
-
completions_rx: &mut UnboundedReceiver<WorkflowActivationCompletion>,
|
|
343
|
+
shutdown_token: CancellationToken,
|
|
296
344
|
activation: WorkflowActivation,
|
|
297
|
-
|
|
345
|
+
completions_tx: &UnboundedSender<WorkflowActivationCompletion>,
|
|
346
|
+
) -> Result<
|
|
347
|
+
Option<WorkflowFutureHandle<impl Future<Output = Result<WorkflowResult<()>, JoinError>>>>,
|
|
348
|
+
anyhow::Error,
|
|
349
|
+
> {
|
|
350
|
+
let mut res = None;
|
|
351
|
+
let run_id = activation.run_id.clone();
|
|
352
|
+
|
|
298
353
|
// If the activation is to start a workflow, create a new workflow driver for it,
|
|
299
354
|
// using the function associated with that workflow id
|
|
300
355
|
if let Some(WorkflowActivationJob {
|
|
@@ -302,8 +357,8 @@ impl WorkflowHalf {
|
|
|
302
357
|
}) = activation.jobs.get(0)
|
|
303
358
|
{
|
|
304
359
|
let workflow_type = &sw.workflow_type;
|
|
305
|
-
let
|
|
306
|
-
|
|
360
|
+
let wf_fns_borrow = self.workflow_fns.borrow();
|
|
361
|
+
let wf_function = wf_fns_borrow
|
|
307
362
|
.get(workflow_type)
|
|
308
363
|
.ok_or_else(|| anyhow!("Workflow type {workflow_type} not found"))?;
|
|
309
364
|
|
|
@@ -314,60 +369,48 @@ impl WorkflowHalf {
|
|
|
314
369
|
sw.arguments.clone(),
|
|
315
370
|
completions_tx.clone(),
|
|
316
371
|
);
|
|
317
|
-
let mut shutdown_rx = shutdown_rx.clone();
|
|
318
372
|
let jh = tokio::spawn(async move {
|
|
319
373
|
tokio::select! {
|
|
320
374
|
r = wff => r,
|
|
321
|
-
|
|
375
|
+
// TODO: This probably shouldn't abort early, as it could cause an in-progress
|
|
376
|
+
// complete to abort. Send synthetic remove activation
|
|
377
|
+
_ = shutdown_token.cancelled() => {
|
|
378
|
+
Ok(WfExitValue::Evicted)
|
|
379
|
+
}
|
|
322
380
|
}
|
|
323
381
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
382
|
+
res = Some(WorkflowFutureHandle {
|
|
383
|
+
join_handle: jh,
|
|
384
|
+
run_id: run_id.clone(),
|
|
385
|
+
});
|
|
386
|
+
self.workflows.borrow_mut().insert(
|
|
387
|
+
run_id.clone(),
|
|
388
|
+
WorkflowData {
|
|
389
|
+
activation_chan: activations,
|
|
390
|
+
},
|
|
391
|
+
);
|
|
327
392
|
}
|
|
328
393
|
|
|
329
394
|
// The activation is expected to apply to some workflow we know about. Use it to
|
|
330
395
|
// unblock things and advance the workflow.
|
|
331
|
-
if let Some(
|
|
332
|
-
|
|
396
|
+
if let Some(dat) = self.workflows.borrow_mut().get_mut(&run_id) {
|
|
397
|
+
dat.activation_chan
|
|
398
|
+
.send(activation)
|
|
333
399
|
.expect("Workflow should exist if we're sending it an activation");
|
|
334
400
|
} else {
|
|
335
401
|
bail!("Got activation for unknown workflow");
|
|
336
402
|
};
|
|
337
403
|
|
|
338
|
-
|
|
339
|
-
if let Some(ref i) = common.worker_interceptor {
|
|
340
|
-
i.on_workflow_activation_completion(&completion);
|
|
341
|
-
}
|
|
342
|
-
common
|
|
343
|
-
.worker
|
|
344
|
-
.complete_workflow_activation(completion)
|
|
345
|
-
.await?;
|
|
346
|
-
Ok(())
|
|
404
|
+
Ok(res)
|
|
347
405
|
}
|
|
348
406
|
}
|
|
349
407
|
|
|
350
|
-
tokio::task_local! {
|
|
351
|
-
// This works, but maybe just passing a context object for activities like WFs is better
|
|
352
|
-
static ACT_CANCEL_TOK: CancellationToken
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/// Returns a future the completes if and when the activity this was called inside has been
|
|
356
|
-
/// cancelled
|
|
357
|
-
pub async fn act_cancelled() {
|
|
358
|
-
ACT_CANCEL_TOK.with(|ct| ct.clone()).cancelled().await
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/// Returns true if this activity has already been cancelled
|
|
362
|
-
pub fn act_is_cancelled() -> bool {
|
|
363
|
-
ACT_CANCEL_TOK.with(|ct| ct.is_cancelled())
|
|
364
|
-
}
|
|
365
|
-
|
|
366
408
|
impl ActivityHalf {
|
|
367
409
|
/// Spawns off a task to handle the provided activity task
|
|
368
410
|
fn activity_task_handler(
|
|
369
411
|
&mut self,
|
|
370
412
|
worker: Arc<dyn CoreWorker>,
|
|
413
|
+
task_queue: String,
|
|
371
414
|
activity: ActivityTask,
|
|
372
415
|
) -> Result<(), anyhow::Error> {
|
|
373
416
|
match activity.variant {
|
|
@@ -383,13 +426,14 @@ impl ActivityHalf {
|
|
|
383
426
|
})?
|
|
384
427
|
.clone();
|
|
385
428
|
let ct = CancellationToken::new();
|
|
429
|
+
let task_token = activity.task_token;
|
|
386
430
|
self.task_tokens_to_cancels
|
|
387
|
-
.insert(
|
|
431
|
+
.insert(task_token.clone().into(), ct.clone());
|
|
388
432
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
let output = (act_fn.act_func)(arg).await;
|
|
433
|
+
let (ctx, arg) =
|
|
434
|
+
ActContext::new(worker.clone(), ct, task_queue, task_token.clone(), start);
|
|
435
|
+
tokio::spawn(async move {
|
|
436
|
+
let output = (act_fn.act_func)(ctx, arg).await;
|
|
393
437
|
let result = match output {
|
|
394
438
|
Ok(res) => ActivityExecutionResult::ok(res),
|
|
395
439
|
Err(err) => match err.downcast::<ActivityCancelledError>() {
|
|
@@ -399,12 +443,12 @@ impl ActivityHalf {
|
|
|
399
443
|
};
|
|
400
444
|
worker
|
|
401
445
|
.complete_activity_task(ActivityTaskCompletion {
|
|
402
|
-
task_token
|
|
446
|
+
task_token,
|
|
403
447
|
result: Some(result),
|
|
404
448
|
})
|
|
405
449
|
.await?;
|
|
406
450
|
Result::<_, anyhow::Error>::Ok(())
|
|
407
|
-
})
|
|
451
|
+
});
|
|
408
452
|
}
|
|
409
453
|
Some(activity_task::Variant::Cancel(_)) => {
|
|
410
454
|
if let Some(ct) = self.task_tokens_to_cancels.get(&activity.task_token.into()) {
|
|
@@ -622,8 +666,9 @@ impl<T: Debug> WfExitValue<T> {
|
|
|
622
666
|
}
|
|
623
667
|
}
|
|
624
668
|
|
|
625
|
-
type BoxActFn =
|
|
626
|
-
|
|
669
|
+
type BoxActFn = Arc<
|
|
670
|
+
dyn Fn(ActContext, Payload) -> BoxFuture<'static, Result<Payload, anyhow::Error>> + Send + Sync,
|
|
671
|
+
>;
|
|
627
672
|
/// Container for user-defined activity functions
|
|
628
673
|
#[derive(Clone)]
|
|
629
674
|
pub struct ActivityFunction {
|
|
@@ -650,16 +695,16 @@ pub trait IntoActivityFunc<Args, Res> {
|
|
|
650
695
|
|
|
651
696
|
impl<A, Rf, R, F> IntoActivityFunc<A, Rf> for F
|
|
652
697
|
where
|
|
653
|
-
F: (Fn(A) -> Rf) + Sync + Send + 'static,
|
|
698
|
+
F: (Fn(ActContext, A) -> Rf) + Sync + Send + 'static,
|
|
654
699
|
A: FromJsonPayloadExt + Send,
|
|
655
700
|
Rf: Future<Output = Result<R, anyhow::Error>> + Send + 'static,
|
|
656
701
|
R: AsJsonPayloadExt,
|
|
657
702
|
{
|
|
658
703
|
fn into_activity_fn(self) -> BoxActFn {
|
|
659
|
-
let wrapper = move |input: Payload| {
|
|
704
|
+
let wrapper = move |ctx: ActContext, input: Payload| {
|
|
660
705
|
// Some minor gymnastics are required to avoid needing to clone the function
|
|
661
706
|
match A::from_json_payload(&input) {
|
|
662
|
-
Ok(deser) => (self)(deser)
|
|
707
|
+
Ok(deser) => (self)(ctx, deser)
|
|
663
708
|
.map(|r| r.map(|r| r.as_json_payload())?)
|
|
664
709
|
.boxed(),
|
|
665
710
|
Err(e) => async move { Err(e.into()) }.boxed(),
|
|
@@ -117,17 +117,13 @@ impl HistoryInfo {
|
|
|
117
117
|
/// Remove events from the beginning of this history such that it looks like what would've been
|
|
118
118
|
/// delivered on a sticky queue where the previously started task was the one before the last
|
|
119
119
|
/// task in this history.
|
|
120
|
-
///
|
|
121
|
-
/// This is not *fully* accurate in that it will include commands that were part of the last
|
|
122
|
-
/// WFT completion, which the server would typically not include, but it's good enough for
|
|
123
|
-
/// testing.
|
|
124
120
|
pub fn make_incremental(&mut self) {
|
|
125
121
|
let last_complete_ix = self
|
|
126
122
|
.events
|
|
127
123
|
.iter()
|
|
128
124
|
.rposition(|he| he.event_type() == EventType::WorkflowTaskCompleted)
|
|
129
125
|
.expect("Must be a WFT completed event in history");
|
|
130
|
-
self.events.drain(0
|
|
126
|
+
self.events.drain(0..last_complete_ix);
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
pub fn events(&self) -> &[HistoryEvent] {
|
|
@@ -223,7 +219,7 @@ mod tests {
|
|
|
223
219
|
fn incremental_works() {
|
|
224
220
|
let t = single_timer("timer1");
|
|
225
221
|
let hi = t.get_one_wft(2).unwrap();
|
|
226
|
-
assert_eq!(hi.events().len(),
|
|
227
|
-
assert_eq!(hi.events()[0].event_id,
|
|
222
|
+
assert_eq!(hi.events().len(), 5);
|
|
223
|
+
assert_eq!(hi.events()[0].event_id, 4);
|
|
228
224
|
}
|
|
229
225
|
}
|