@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
|
@@ -336,7 +336,7 @@ mod test {
|
|
|
336
336
|
happy_wfm.shutdown().await.unwrap();
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
#[tokio::test
|
|
339
|
+
#[tokio::test]
|
|
340
340
|
async fn mismatched_timer_ids_errors() {
|
|
341
341
|
let func = WorkflowFunction::new(|command_sink: WfContext| async move {
|
|
342
342
|
command_sink.timer(Duration::from_secs(5)).await;
|
|
@@ -403,7 +403,7 @@ mod test {
|
|
|
403
403
|
wfm.shutdown().await.unwrap();
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
#[tokio::test
|
|
406
|
+
#[tokio::test]
|
|
407
407
|
async fn cancel_before_sent_to_server() {
|
|
408
408
|
let func = WorkflowFunction::new(|ctx: WfContext| async move {
|
|
409
409
|
let cancel_timer_fut = ctx.timer(Duration::from_secs(500));
|
|
@@ -252,7 +252,11 @@ impl WorkflowMachines {
|
|
|
252
252
|
|
|
253
253
|
/// Let this workflow know that something we've been waiting locally on has resolved, like a
|
|
254
254
|
/// local activity or side effect
|
|
255
|
-
|
|
255
|
+
///
|
|
256
|
+
/// Returns true if the resolution did anything. EX: If the activity is already canceled and
|
|
257
|
+
/// used the TryCancel or Abandon modes, the resolution is uninteresting.
|
|
258
|
+
pub(crate) fn local_resolution(&mut self, resolution: LocalResolution) -> Result<bool> {
|
|
259
|
+
let mut result_important = true;
|
|
256
260
|
match resolution {
|
|
257
261
|
LocalResolution::LocalActivity(LocalActivityResolution {
|
|
258
262
|
seq,
|
|
@@ -268,6 +272,9 @@ impl WorkflowMachines {
|
|
|
268
272
|
if let Machines::LocalActivityMachine(ref mut lam) = *mach {
|
|
269
273
|
let resps =
|
|
270
274
|
lam.try_resolve(result, runtime, attempt, backoff, original_schedule_time)?;
|
|
275
|
+
if resps.is_empty() {
|
|
276
|
+
result_important = false;
|
|
277
|
+
}
|
|
271
278
|
self.process_machine_responses(mk, resps)?;
|
|
272
279
|
} else {
|
|
273
280
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
@@ -279,7 +286,7 @@ impl WorkflowMachines {
|
|
|
279
286
|
self.local_activity_data.done_executing(seq);
|
|
280
287
|
}
|
|
281
288
|
}
|
|
282
|
-
Ok(
|
|
289
|
+
Ok(result_important)
|
|
283
290
|
}
|
|
284
291
|
|
|
285
292
|
/// Drain all queued local activities that need executing or cancellation
|
|
@@ -456,7 +463,7 @@ impl WorkflowMachines {
|
|
|
456
463
|
event: HistoryEvent,
|
|
457
464
|
has_next_event: bool,
|
|
458
465
|
) -> Result<()> {
|
|
459
|
-
|
|
466
|
+
trace!(
|
|
460
467
|
event = %event,
|
|
461
468
|
"handling non-stateful event"
|
|
462
469
|
);
|
|
@@ -470,6 +477,10 @@ impl WorkflowMachines {
|
|
|
470
477
|
if let Some(st) = event.event_time {
|
|
471
478
|
let as_systime: SystemTime = st.try_into()?;
|
|
472
479
|
self.workflow_start_time = Some(as_systime);
|
|
480
|
+
// Set the workflow time to be the event time of the first event, so that
|
|
481
|
+
// if there is a query issued before first WFT started event, there is some
|
|
482
|
+
// workflow time set.
|
|
483
|
+
self.set_current_time(as_systime);
|
|
473
484
|
}
|
|
474
485
|
// Notify the lang sdk that it's time to kick off a workflow
|
|
475
486
|
self.drive_me.start(
|
|
@@ -96,7 +96,10 @@ impl WorkflowManager {
|
|
|
96
96
|
|
|
97
97
|
/// Let this workflow know that something we've been waiting locally on has resolved, like a
|
|
98
98
|
/// local activity or side effect
|
|
99
|
-
|
|
99
|
+
///
|
|
100
|
+
/// Returns true if the resolution did anything. EX: If the activity is already canceled and
|
|
101
|
+
/// used the TryCancel or Abandon modes, the resolution is uninteresting.
|
|
102
|
+
pub fn notify_of_local_result(&mut self, resolved: LocalResolution) -> Result<bool> {
|
|
100
103
|
self.machines.local_resolution(resolved)
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -407,7 +410,7 @@ pub mod managed_wf {
|
|
|
407
410
|
&mut self,
|
|
408
411
|
seq_num: u32,
|
|
409
412
|
result: ActivityExecutionResult,
|
|
410
|
-
) -> Result<
|
|
413
|
+
) -> Result<bool> {
|
|
411
414
|
self.mgr
|
|
412
415
|
.notify_of_local_result(LocalResolution::LocalActivity(LocalActivityResolution {
|
|
413
416
|
seq: seq_num,
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
use crate::{telemetry::metrics::MetricsContext, workflow::WorkflowCachingPolicy};
|
|
2
2
|
use lru::LruCache;
|
|
3
|
+
use std::{
|
|
4
|
+
future::Future,
|
|
5
|
+
sync::{
|
|
6
|
+
atomic::{AtomicUsize, Ordering},
|
|
7
|
+
Arc,
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
use tokio::sync::Notify;
|
|
3
11
|
|
|
4
12
|
/// Helps to maintain an LRU ordering in which workflow runs have been accessed so that old runs may
|
|
5
13
|
/// be evicted once we reach the cap.
|
|
@@ -7,6 +15,9 @@ use lru::LruCache;
|
|
|
7
15
|
pub(crate) struct WorkflowCacheManager {
|
|
8
16
|
cache: LruCache<String, ()>,
|
|
9
17
|
metrics: MetricsContext,
|
|
18
|
+
cap_notify: Arc<Notify>,
|
|
19
|
+
cache_size: Arc<AtomicUsize>,
|
|
20
|
+
cap_mutex: Arc<tokio::sync::Mutex<()>>,
|
|
10
21
|
}
|
|
11
22
|
|
|
12
23
|
impl WorkflowCacheManager {
|
|
@@ -20,6 +31,9 @@ impl WorkflowCacheManager {
|
|
|
20
31
|
Self {
|
|
21
32
|
cache: LruCache::new(cap),
|
|
22
33
|
metrics,
|
|
34
|
+
cap_notify: Arc::new(Notify::new()),
|
|
35
|
+
cache_size: Arc::new(AtomicUsize::new(0)),
|
|
36
|
+
cap_mutex: Arc::new(tokio::sync::Mutex::new(())),
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
39
|
|
|
@@ -28,6 +42,30 @@ impl WorkflowCacheManager {
|
|
|
28
42
|
Self::new(policy, Default::default())
|
|
29
43
|
}
|
|
30
44
|
|
|
45
|
+
/// Resolves once there is an open slot in the cache. The passed in closure can be used to
|
|
46
|
+
/// exit the wait loop if it returns true even if the cache is not below the limit. It will be
|
|
47
|
+
/// re-evaluated every time there is an insert or remove to the cache, even if it did not change
|
|
48
|
+
/// the size.
|
|
49
|
+
pub fn wait_for_capacity<Fun>(&self, early_exit: Fun) -> Option<impl Future<Output = ()>>
|
|
50
|
+
where
|
|
51
|
+
Fun: Fn() -> bool,
|
|
52
|
+
{
|
|
53
|
+
if self.cache.cap() == 0 {
|
|
54
|
+
return None;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let size = self.cache_size.clone();
|
|
58
|
+
let notify = self.cap_notify.clone();
|
|
59
|
+
let cap = self.cache.cap();
|
|
60
|
+
let mx = self.cap_mutex.clone();
|
|
61
|
+
Some(async move {
|
|
62
|
+
let _l = mx.lock().await;
|
|
63
|
+
while !early_exit() && size.load(Ordering::Acquire) >= cap {
|
|
64
|
+
notify.notified().await;
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
31
69
|
/// Inserts a record associated with the run id into the lru cache.
|
|
32
70
|
/// Once cache reaches capacity, overflow records will be returned back to the caller.
|
|
33
71
|
pub fn insert(&mut self, run_id: &str) -> Option<String> {
|
|
@@ -44,7 +82,7 @@ impl WorkflowCacheManager {
|
|
|
44
82
|
not_cached.then(|| maybe_got_evicted).flatten()
|
|
45
83
|
};
|
|
46
84
|
|
|
47
|
-
self.
|
|
85
|
+
self.size_changed();
|
|
48
86
|
|
|
49
87
|
res
|
|
50
88
|
}
|
|
@@ -56,7 +94,14 @@ impl WorkflowCacheManager {
|
|
|
56
94
|
|
|
57
95
|
pub fn remove(&mut self, run_id: &str) {
|
|
58
96
|
self.cache.pop(run_id);
|
|
59
|
-
self.
|
|
97
|
+
self.size_changed();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fn size_changed(&self) {
|
|
101
|
+
let size = self.cache.len();
|
|
102
|
+
self.metrics.cache_size(size as u64);
|
|
103
|
+
self.cache_size.store(size, Ordering::Release);
|
|
104
|
+
self.cap_notify.notify_one();
|
|
60
105
|
}
|
|
61
106
|
}
|
|
62
107
|
|
|
@@ -154,7 +154,7 @@ impl WorkflowConcurrencyManager {
|
|
|
154
154
|
pub fn complete_wft(
|
|
155
155
|
&self,
|
|
156
156
|
run_id: &str,
|
|
157
|
-
|
|
157
|
+
sent_wft_complete_to_srv: bool,
|
|
158
158
|
) -> Option<OutstandingTask> {
|
|
159
159
|
// If the WFT completion wasn't sent to the server, but we did see the final event, we still
|
|
160
160
|
// want to clear the workflow task. This can really only happen in replay testing, where we
|
|
@@ -164,7 +164,7 @@ impl WorkflowConcurrencyManager {
|
|
|
164
164
|
let saw_final = self
|
|
165
165
|
.access_sync(run_id, |wfm| wfm.machines.have_seen_terminal_event)
|
|
166
166
|
.unwrap_or_default();
|
|
167
|
-
if !saw_final && !
|
|
167
|
+
if !saw_final && !sent_wft_complete_to_srv {
|
|
168
168
|
return None;
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -313,6 +313,7 @@ impl WorkflowConcurrencyManager {
|
|
|
313
313
|
val.and_then(|v| v.buffered_resp.take())
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
/// Sounds the total number of outstanding workflow tasks
|
|
316
317
|
pub fn outstanding_wft(&self) -> usize {
|
|
317
318
|
self.runs
|
|
318
319
|
.read()
|
|
@@ -320,6 +321,19 @@ impl WorkflowConcurrencyManager {
|
|
|
320
321
|
.filter(|(_, run)| run.wft.is_some())
|
|
321
322
|
.count()
|
|
322
323
|
}
|
|
324
|
+
|
|
325
|
+
/// Returns number of currently cached workflows
|
|
326
|
+
pub fn cached_workflows(&self) -> usize {
|
|
327
|
+
self.runs.read().len()
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/// Returns true if any outstanding activation contains an eviction
|
|
331
|
+
pub fn are_outstanding_evictions(&self) -> bool {
|
|
332
|
+
self.runs
|
|
333
|
+
.read()
|
|
334
|
+
.values()
|
|
335
|
+
.any(|mr| mr.activation.map(|a| a.has_eviction()).unwrap_or_default())
|
|
336
|
+
}
|
|
323
337
|
}
|
|
324
338
|
|
|
325
339
|
#[cfg(test)]
|