@temporalio/core-bridge 1.5.2 → 1.6.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 +255 -48
- package/package.json +4 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/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/pipeline.yml +1 -3
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +28 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +9 -5
- package/sdk-core/client/src/lib.rs +211 -36
- package/sdk-core/client/src/raw.rs +1 -1
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +23 -9
- package/sdk-core/core/src/abstractions.rs +11 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +6 -5
- package/sdk-core/core/src/core_tests/local_activities.rs +263 -22
- package/sdk-core/core/src/core_tests/queries.rs +2 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +249 -5
- package/sdk-core/core/src/ephemeral_server/mod.rs +5 -6
- package/sdk-core/core/src/lib.rs +2 -0
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/mod.rs +23 -8
- package/sdk-core/core/src/test_help/mod.rs +8 -1
- package/sdk-core/core/src/worker/activities/local_activities.rs +259 -125
- package/sdk-core/core/src/worker/activities.rs +3 -2
- package/sdk-core/core/src/worker/mod.rs +53 -26
- package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- package/sdk-core/core/src/worker/workflow/history_update.rs +835 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -17
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +73 -51
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -3
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +89 -58
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -7
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +21 -9
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1021 -360
- package/sdk-core/core/src/worker/workflow/mod.rs +306 -346
- package/sdk-core/core/src/worker/workflow/run_cache.rs +29 -53
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +115 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +444 -714
- package/sdk-core/core-api/Cargo.toml +2 -0
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +6 -2
- package/sdk-core/core-api/src/worker.rs +14 -1
- package/sdk-core/etc/deps.svg +115 -140
- package/sdk-core/etc/regen-depgraph.sh +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -6
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -3
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- package/sdk-core/protos/api_upstream/Makefile +5 -5
- package/sdk-core/protos/api_upstream/build/go.mod +7 -0
- package/sdk-core/protos/api_upstream/build/go.sum +5 -0
- package/sdk-core/protos/api_upstream/build/tools.go +29 -0
- package/sdk-core/protos/api_upstream/go.mod +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +12 -19
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +3 -3
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -2
- package/sdk-core/protos/api_upstream/temporal/api/{update/v1/message.proto → enums/v1/interaction_type.proto} +11 -18
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +2 -13
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -19
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +13 -8
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- package/sdk-core/sdk/Cargo.toml +4 -3
- package/sdk-core/sdk/src/lib.rs +87 -21
- package/sdk-core/sdk/src/workflow_future.rs +7 -12
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- package/sdk-core/sdk-core-protos/build.rs +36 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +26 -19
- package/sdk-core/sdk-core-protos/src/history_info.rs +4 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +78 -34
- package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +50 -18
- package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- package/sdk-core/test-utils/src/workflows.rs +29 -0
- package/sdk-core/tests/fuzzy_workflow.rs +130 -0
- package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +114 -7
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -2
- package/sdk-core/tests/integ_tests/metrics_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -39
- package/sdk-core/tests/integ_tests/queries_tests.rs +2 -127
- package/sdk-core/tests/integ_tests/visibility_tests.rs +52 -5
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +74 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +5 -13
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +2 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +69 -197
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +4 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +5 -6
- package/sdk-core/tests/main.rs +2 -12
- package/sdk-core/tests/runner.rs +71 -34
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/sdk-core/bridge-ffi/Cargo.toml +0 -24
- package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- package/sdk-core/bridge-ffi/build.rs +0 -25
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
- package/sdk-core/bridge-ffi/src/lib.rs +0 -746
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- package/sdk-core/sdk/src/conversions.rs +0 -8
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
telemetry::metrics::workflow_type,
|
|
3
3
|
worker::workflow::{
|
|
4
|
-
managed_run::
|
|
5
|
-
|
|
4
|
+
managed_run::{ManagedRun, RunUpdateAct},
|
|
5
|
+
HistoryUpdate, LocalActivityRequestSink, PermittedWFT,
|
|
6
6
|
},
|
|
7
7
|
MetricsContext,
|
|
8
8
|
};
|
|
9
9
|
use lru::LruCache;
|
|
10
|
-
use std::{num::NonZeroUsize,
|
|
11
|
-
use tokio::sync::mpsc::UnboundedSender;
|
|
10
|
+
use std::{mem, num::NonZeroUsize, sync::Arc};
|
|
12
11
|
|
|
13
12
|
pub(super) struct RunCache {
|
|
14
13
|
max: usize,
|
|
15
14
|
namespace: String,
|
|
16
|
-
run_update_tx: UnboundedSender<RunUpdateResponse>,
|
|
17
15
|
/// Run id -> Data
|
|
18
|
-
runs: LruCache<String,
|
|
19
|
-
local_activity_request_sink: LocalActivityRequestSink
|
|
16
|
+
runs: LruCache<String, ManagedRun>,
|
|
17
|
+
local_activity_request_sink: Arc<dyn LocalActivityRequestSink>,
|
|
20
18
|
|
|
21
19
|
metrics: MetricsContext,
|
|
22
20
|
}
|
|
@@ -25,8 +23,7 @@ impl RunCache {
|
|
|
25
23
|
pub fn new(
|
|
26
24
|
max_cache_size: usize,
|
|
27
25
|
namespace: String,
|
|
28
|
-
|
|
29
|
-
local_activity_request_sink: LocalActivityRequestSink,
|
|
26
|
+
local_activity_request_sink: Arc<dyn LocalActivityRequestSink>,
|
|
30
27
|
metrics: MetricsContext,
|
|
31
28
|
) -> Self {
|
|
32
29
|
// The cache needs room for at least one run, otherwise we couldn't do anything. In
|
|
@@ -39,7 +36,6 @@ impl RunCache {
|
|
|
39
36
|
Self {
|
|
40
37
|
max: max_cache_size,
|
|
41
38
|
namespace,
|
|
42
|
-
run_update_tx,
|
|
43
39
|
runs: LruCache::new(
|
|
44
40
|
NonZeroUsize::new(lru_size).expect("LRU size is guaranteed positive"),
|
|
45
41
|
),
|
|
@@ -48,71 +44,51 @@ impl RunCache {
|
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
pub fn instantiate_or_update(
|
|
52
|
-
&mut self,
|
|
53
|
-
run_id: &str,
|
|
54
|
-
workflow_id: &str,
|
|
55
|
-
wf_type: &str,
|
|
56
|
-
history_update: HistoryUpdate,
|
|
57
|
-
start_time: Instant,
|
|
58
|
-
) -> &mut ManagedRunHandle {
|
|
47
|
+
pub fn instantiate_or_update(&mut self, mut pwft: PermittedWFT) -> RunUpdateAct {
|
|
59
48
|
let cur_num_cached_runs = self.runs.len();
|
|
49
|
+
let run_id = &pwft.work.execution.run_id;
|
|
60
50
|
|
|
61
|
-
if self.runs.
|
|
62
|
-
|
|
63
|
-
// use get_mut above instead of in here (even though we always return from this branch).
|
|
64
|
-
// So, forced to do this.
|
|
65
|
-
let run_handle = self.runs.get_mut(run_id).unwrap();
|
|
66
|
-
|
|
67
|
-
run_handle.metrics.sticky_cache_hit();
|
|
68
|
-
run_handle.incoming_wft(NewIncomingWFT {
|
|
69
|
-
history_update: Some(history_update),
|
|
70
|
-
start_time,
|
|
71
|
-
});
|
|
51
|
+
if let Some(run_handle) = self.runs.get_mut(run_id) {
|
|
52
|
+
let rur = run_handle.incoming_wft(pwft);
|
|
72
53
|
self.metrics.cache_size(cur_num_cached_runs as u64);
|
|
73
|
-
return
|
|
54
|
+
return rur;
|
|
74
55
|
}
|
|
75
56
|
|
|
76
57
|
// Create a new workflow machines instance for this workflow, initialize it, and
|
|
77
58
|
// track it.
|
|
78
59
|
let metrics = self
|
|
79
60
|
.metrics
|
|
80
|
-
.with_new_attrs([workflow_type(
|
|
81
|
-
|
|
61
|
+
.with_new_attrs([workflow_type(pwft.work.workflow_type.clone())]);
|
|
62
|
+
// Replace the update in the wft with a dummy one, since we must instantiate the machines
|
|
63
|
+
// with the update.
|
|
64
|
+
let history_update = mem::replace(&mut pwft.work.update, HistoryUpdate::dummy());
|
|
65
|
+
let mut mrh = ManagedRun::new(
|
|
82
66
|
history_update,
|
|
83
67
|
self.namespace.clone(),
|
|
84
|
-
workflow_id.
|
|
85
|
-
|
|
86
|
-
run_id.
|
|
87
|
-
metrics.clone(),
|
|
88
|
-
);
|
|
89
|
-
let mut mrh = ManagedRunHandle::new(
|
|
90
|
-
wfm,
|
|
91
|
-
self.run_update_tx.clone(),
|
|
68
|
+
pwft.work.execution.workflow_id.clone(),
|
|
69
|
+
pwft.work.workflow_type.clone(),
|
|
70
|
+
pwft.work.execution.run_id.clone(),
|
|
92
71
|
self.local_activity_request_sink.clone(),
|
|
93
72
|
metrics,
|
|
94
73
|
);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
if self.runs.push(run_id.to_string(), mrh).is_some() {
|
|
74
|
+
let run_id = run_id.to_string();
|
|
75
|
+
let rur = mrh.incoming_wft(pwft);
|
|
76
|
+
if self.runs.push(run_id, mrh).is_some() {
|
|
100
77
|
panic!("Overflowed run cache! Cache owner is expected to avoid this!");
|
|
101
78
|
}
|
|
102
79
|
self.metrics.cache_size(cur_num_cached_runs as u64 + 1);
|
|
103
|
-
|
|
104
|
-
self.runs.get_mut(run_id).unwrap()
|
|
80
|
+
rur
|
|
105
81
|
}
|
|
106
|
-
pub fn remove(&mut self, k: &str) -> Option<
|
|
82
|
+
pub fn remove(&mut self, k: &str) -> Option<ManagedRun> {
|
|
107
83
|
let r = self.runs.pop(k);
|
|
108
84
|
self.metrics.cache_size(self.len() as u64);
|
|
109
85
|
r
|
|
110
86
|
}
|
|
111
87
|
|
|
112
|
-
pub fn get_mut(&mut self, k: &str) -> Option<&mut
|
|
88
|
+
pub fn get_mut(&mut self, k: &str) -> Option<&mut ManagedRun> {
|
|
113
89
|
self.runs.get_mut(k)
|
|
114
90
|
}
|
|
115
|
-
pub fn get(&mut self, k: &str) -> Option<&
|
|
91
|
+
pub fn get(&mut self, k: &str) -> Option<&ManagedRun> {
|
|
116
92
|
self.runs.get(k)
|
|
117
93
|
}
|
|
118
94
|
|
|
@@ -121,16 +97,16 @@ impl RunCache {
|
|
|
121
97
|
self.runs.peek_lru().map(|(run_id, _)| run_id.as_str())
|
|
122
98
|
}
|
|
123
99
|
/// Returns an iterator yielding cached runs in LRU order
|
|
124
|
-
pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &
|
|
100
|
+
pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &ManagedRun)> {
|
|
125
101
|
self.runs.iter().rev().map(|(k, v)| (k.as_str(), v))
|
|
126
102
|
}
|
|
127
|
-
pub fn peek(&self, k: &str) -> Option<&
|
|
103
|
+
pub fn peek(&self, k: &str) -> Option<&ManagedRun> {
|
|
128
104
|
self.runs.peek(k)
|
|
129
105
|
}
|
|
130
106
|
pub fn has_run(&self, k: &str) -> bool {
|
|
131
107
|
self.runs.contains(k)
|
|
132
108
|
}
|
|
133
|
-
pub fn handles(&self) -> impl Iterator<Item = &
|
|
109
|
+
pub fn handles(&self) -> impl Iterator<Item = &ManagedRun> {
|
|
134
110
|
self.runs.iter().map(|(_, v)| v)
|
|
135
111
|
}
|
|
136
112
|
pub fn is_full(&self) -> bool {
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
abstractions::OwnedMeteredSemPermit,
|
|
3
|
+
protosext::ValidPollWFTQResponse,
|
|
4
|
+
worker::{
|
|
5
|
+
client::WorkerClient,
|
|
6
|
+
workflow::{
|
|
7
|
+
history_update::HistoryPaginator, CacheMissFetchReq, HistoryUpdate, NextPageReq,
|
|
8
|
+
PermittedWFT,
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
use futures::Stream;
|
|
13
|
+
use futures_util::{stream, stream::PollNext, FutureExt, StreamExt};
|
|
14
|
+
use std::{future, sync::Arc};
|
|
15
|
+
use tracing::Span;
|
|
16
|
+
|
|
17
|
+
/// Transforms incoming validated WFTs and history fetching requests into [PermittedWFT]s ready
|
|
18
|
+
/// for application to workflow state
|
|
19
|
+
pub(super) struct WFTExtractor {}
|
|
20
|
+
|
|
21
|
+
pub(super) enum WFTExtractorOutput {
|
|
22
|
+
NewWFT(PermittedWFT),
|
|
23
|
+
FetchResult(PermittedWFT, Arc<HistfetchRC>),
|
|
24
|
+
NextPage {
|
|
25
|
+
paginator: HistoryPaginator,
|
|
26
|
+
update: HistoryUpdate,
|
|
27
|
+
span: Span,
|
|
28
|
+
rc: Arc<HistfetchRC>,
|
|
29
|
+
},
|
|
30
|
+
FailedFetch {
|
|
31
|
+
run_id: String,
|
|
32
|
+
err: tonic::Status,
|
|
33
|
+
},
|
|
34
|
+
PollerDead,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type WFTStreamIn = (
|
|
38
|
+
Result<ValidPollWFTQResponse, tonic::Status>,
|
|
39
|
+
OwnedMeteredSemPermit,
|
|
40
|
+
);
|
|
41
|
+
#[derive(derive_more::From, Debug)]
|
|
42
|
+
pub(super) enum HistoryFetchReq {
|
|
43
|
+
Full(CacheMissFetchReq, Arc<HistfetchRC>),
|
|
44
|
+
NextPage(NextPageReq, Arc<HistfetchRC>),
|
|
45
|
+
}
|
|
46
|
+
/// Used inside of `Arc`s to ensure we don't shutdown while there are outstanding fetches.
|
|
47
|
+
#[derive(Debug)]
|
|
48
|
+
pub(super) struct HistfetchRC {}
|
|
49
|
+
|
|
50
|
+
impl WFTExtractor {
|
|
51
|
+
pub(super) fn build(
|
|
52
|
+
client: Arc<dyn WorkerClient>,
|
|
53
|
+
max_fetch_concurrency: usize,
|
|
54
|
+
wft_stream: impl Stream<Item = WFTStreamIn> + Send + 'static,
|
|
55
|
+
fetch_stream: impl Stream<Item = HistoryFetchReq> + Send + 'static,
|
|
56
|
+
) -> impl Stream<Item = Result<WFTExtractorOutput, tonic::Status>> + Send + 'static {
|
|
57
|
+
let fetch_client = client.clone();
|
|
58
|
+
let wft_stream = wft_stream
|
|
59
|
+
.map(move |(wft, permit)| {
|
|
60
|
+
let client = client.clone();
|
|
61
|
+
async move {
|
|
62
|
+
match wft {
|
|
63
|
+
Ok(wft) => {
|
|
64
|
+
let run_id = wft.workflow_execution.run_id.clone();
|
|
65
|
+
Ok(match HistoryPaginator::from_poll(wft, client).await {
|
|
66
|
+
Ok((pag, prep)) => WFTExtractorOutput::NewWFT(PermittedWFT {
|
|
67
|
+
work: prep,
|
|
68
|
+
permit,
|
|
69
|
+
paginator: pag,
|
|
70
|
+
}),
|
|
71
|
+
Err(err) => WFTExtractorOutput::FailedFetch { run_id, err },
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
Err(e) => Err(e),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// This is... unattractive, but lets us avoid boxing all the futs in the stream
|
|
78
|
+
.left_future()
|
|
79
|
+
.left_future()
|
|
80
|
+
})
|
|
81
|
+
.chain(stream::iter([future::ready(Ok(
|
|
82
|
+
WFTExtractorOutput::PollerDead,
|
|
83
|
+
))
|
|
84
|
+
.right_future()
|
|
85
|
+
.left_future()]));
|
|
86
|
+
|
|
87
|
+
stream::select_with_strategy(
|
|
88
|
+
wft_stream,
|
|
89
|
+
fetch_stream.map(move |fetchreq: HistoryFetchReq| {
|
|
90
|
+
let client = fetch_client.clone();
|
|
91
|
+
async move {
|
|
92
|
+
Ok(match fetchreq {
|
|
93
|
+
// It's OK to simply drop the refcounters in the event of fetch
|
|
94
|
+
// failure. We'll just proceed with shutdown.
|
|
95
|
+
HistoryFetchReq::Full(req, rc) => {
|
|
96
|
+
let run_id = req.original_wft.work.execution.run_id.clone();
|
|
97
|
+
match HistoryPaginator::from_fetchreq(req, client).await {
|
|
98
|
+
Ok(r) => WFTExtractorOutput::FetchResult(r, rc),
|
|
99
|
+
Err(err) => WFTExtractorOutput::FailedFetch { run_id, err },
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
HistoryFetchReq::NextPage(mut req, rc) => {
|
|
103
|
+
match req.paginator.extract_next_update().await {
|
|
104
|
+
Ok(update) => WFTExtractorOutput::NextPage {
|
|
105
|
+
paginator: req.paginator,
|
|
106
|
+
update,
|
|
107
|
+
span: req.span,
|
|
108
|
+
rc,
|
|
109
|
+
},
|
|
110
|
+
Err(err) => WFTExtractorOutput::FailedFetch {
|
|
111
|
+
run_id: req.paginator.run_id,
|
|
112
|
+
err,
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
.right_future()
|
|
119
|
+
}),
|
|
120
|
+
// Priority always goes to the fetching stream
|
|
121
|
+
|_: &mut ()| PollNext::Right,
|
|
122
|
+
)
|
|
123
|
+
.buffer_unordered(max_fetch_concurrency)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -47,10 +47,7 @@ pub(crate) fn validate_wft(
|
|
|
47
47
|
wft.try_into().map_err(|resp| {
|
|
48
48
|
tonic::Status::new(
|
|
49
49
|
tonic::Code::DataLoss,
|
|
50
|
-
format!(
|
|
51
|
-
"Server returned a poll WFT response we couldn't interpret: {:?}",
|
|
52
|
-
resp
|
|
53
|
-
),
|
|
50
|
+
format!("Server returned a poll WFT response we couldn't interpret: {resp:?}"),
|
|
54
51
|
)
|
|
55
52
|
})
|
|
56
53
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
telemetry::metrics::MetricsContext,
|
|
3
|
+
worker::{
|
|
4
|
+
workflow::{
|
|
5
|
+
workflow_stream::{WFStream, WFStreamInput},
|
|
6
|
+
LAReqSink, LocalActivityRequestSink,
|
|
7
|
+
},
|
|
8
|
+
LocalActRequest, LocalActivityResolution,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
use crossbeam::queue::SegQueue;
|
|
12
|
+
use futures::Stream;
|
|
13
|
+
use futures_util::StreamExt;
|
|
14
|
+
use serde::{Deserialize, Serialize};
|
|
15
|
+
use std::{future, sync::Arc};
|
|
16
|
+
use temporal_sdk_core_api::worker::WorkerConfig;
|
|
17
|
+
use tokio::sync::mpsc::UnboundedSender;
|
|
18
|
+
use tokio_util::sync::CancellationToken;
|
|
19
|
+
|
|
20
|
+
/// Replay everything that happened to internal workflow state. Useful for 100% deterministic
|
|
21
|
+
/// reproduction of bugs.
|
|
22
|
+
///
|
|
23
|
+
/// Use `CoreWfStarter::enable_wf_state_input_recording` from the integration test utilities to
|
|
24
|
+
/// activate saving the data to disk, and use the `wf_input_replay` example binary to replay.
|
|
25
|
+
pub async fn replay_wf_state_inputs(mut config: WorkerConfig, inputs: impl Stream<Item = Vec<u8>>) {
|
|
26
|
+
use crate::worker::build_wf_basics;
|
|
27
|
+
|
|
28
|
+
let la_resp_q = Arc::new(SegQueue::new());
|
|
29
|
+
let la_resp_q_clone = la_resp_q.clone();
|
|
30
|
+
let inputs = inputs
|
|
31
|
+
.map(|bytes| {
|
|
32
|
+
rmp_serde::from_slice::<StoredWFStateInputDeSer>(&bytes)
|
|
33
|
+
.expect("Can decode wf stream input")
|
|
34
|
+
})
|
|
35
|
+
.filter_map(|si| {
|
|
36
|
+
future::ready(match si {
|
|
37
|
+
StoredWFStateInputDeSer::Stream(wfsi) => Some(wfsi),
|
|
38
|
+
StoredWFStateInputDeSer::ImmediateLASinkResolutions(lares) => {
|
|
39
|
+
la_resp_q_clone.push(lares);
|
|
40
|
+
None
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
let basics = build_wf_basics(
|
|
45
|
+
&mut config,
|
|
46
|
+
MetricsContext::no_op(),
|
|
47
|
+
CancellationToken::new(),
|
|
48
|
+
);
|
|
49
|
+
let sink = ReadingFromFileLaReqSink {
|
|
50
|
+
resolutions: la_resp_q,
|
|
51
|
+
};
|
|
52
|
+
info!("Beginning workflow stream internal state replay");
|
|
53
|
+
let stream = WFStream::build_internal(inputs, basics, sink);
|
|
54
|
+
stream
|
|
55
|
+
.for_each(|o| async move { trace!("Stream output: {:?}", o) })
|
|
56
|
+
.await;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
impl WFStream {
|
|
60
|
+
pub(super) fn prep_input(&mut self, action: &WFStreamInput) -> Option<PreppedInputWrite> {
|
|
61
|
+
// Remove the channel, we'll put it back, avoiding a clone
|
|
62
|
+
self.wf_state_inputs.take().map(|chan| PreppedInputWrite {
|
|
63
|
+
data: rmp_serde::to_vec(&StoredWFStateInputSer::Stream(action))
|
|
64
|
+
.expect("WF Inputs are serializable"),
|
|
65
|
+
chan,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
pub(super) fn flush_write(&mut self, w: PreppedInputWrite) {
|
|
69
|
+
let _ = w.chan.send(w.data);
|
|
70
|
+
self.wf_state_inputs = Some(w.chan);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
pub(super) struct PreppedInputWrite {
|
|
74
|
+
data: Vec<u8>,
|
|
75
|
+
chan: UnboundedSender<Vec<u8>>,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#[derive(Serialize)]
|
|
79
|
+
enum StoredWFStateInputSer<'a> {
|
|
80
|
+
Stream(&'a WFStreamInput),
|
|
81
|
+
ImmediateLASinkResolutions(&'a Vec<LocalActivityResolution>),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[derive(Deserialize)]
|
|
85
|
+
enum StoredWFStateInputDeSer {
|
|
86
|
+
Stream(WFStreamInput),
|
|
87
|
+
ImmediateLASinkResolutions(Vec<LocalActivityResolution>),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
struct ReadingFromFileLaReqSink {
|
|
91
|
+
resolutions: Arc<SegQueue<Vec<LocalActivityResolution>>>,
|
|
92
|
+
}
|
|
93
|
+
impl LocalActivityRequestSink for ReadingFromFileLaReqSink {
|
|
94
|
+
fn sink_reqs(&self, reqs: Vec<LocalActRequest>) -> Vec<LocalActivityResolution> {
|
|
95
|
+
if !reqs.is_empty() {
|
|
96
|
+
self.resolutions
|
|
97
|
+
.pop()
|
|
98
|
+
.expect("LA sink was called, but there's no stored immediate response")
|
|
99
|
+
} else {
|
|
100
|
+
vec![]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl LAReqSink {
|
|
106
|
+
pub(crate) fn write_req(&self, res: &Vec<LocalActivityResolution>) {
|
|
107
|
+
if let Some(r) = self.recorder.as_ref() {
|
|
108
|
+
r.send(
|
|
109
|
+
rmp_serde::to_vec(&StoredWFStateInputSer::ImmediateLASinkResolutions(res))
|
|
110
|
+
.expect("LA immediate resolutions are serializable"),
|
|
111
|
+
)
|
|
112
|
+
.expect("WF input serialization channel is available for immediate LA result storage");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
use tonic::{Code, Status};
|
|
2
|
+
|
|
3
|
+
#[derive(serde::Serialize, serde::Deserialize)]
|
|
4
|
+
#[serde(remote = "Status")]
|
|
5
|
+
pub(super) struct SerdeStatus {
|
|
6
|
+
#[serde(getter = "get_code")]
|
|
7
|
+
code: i32,
|
|
8
|
+
#[serde(getter = "get_owned_msg")]
|
|
9
|
+
message: String,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fn get_owned_msg(v: &Status) -> String {
|
|
13
|
+
v.message().to_string()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn get_code(v: &Status) -> i32 {
|
|
17
|
+
v.code() as i32
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
impl From<SerdeStatus> for Status {
|
|
21
|
+
fn from(v: SerdeStatus) -> Self {
|
|
22
|
+
Status::new(Code::from(v.code), v.message)
|
|
23
|
+
}
|
|
24
|
+
}
|