temporalio 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -23
- data/bridge/Cargo.lock +168 -59
- data/bridge/Cargo.toml +4 -2
- data/bridge/sdk-core/README.md +19 -6
- data/bridge/sdk-core/client/src/lib.rs +215 -39
- data/bridge/sdk-core/client/src/metrics.rs +17 -8
- data/bridge/sdk-core/client/src/raw.rs +4 -4
- data/bridge/sdk-core/client/src/retry.rs +32 -20
- data/bridge/sdk-core/core/Cargo.toml +22 -9
- data/bridge/sdk-core/core/src/abstractions.rs +203 -14
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
- data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
- data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
- data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
- data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
- data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
- data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
- data/bridge/sdk-core/core/src/lib.rs +16 -9
- data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
- data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
- data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
- data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
- data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
- data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
- data/bridge/sdk-core/core/src/worker/client.rs +18 -2
- data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
- data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
- data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
- data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
- data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
- data/bridge/sdk-core/core-api/Cargo.toml +2 -1
- data/bridge/sdk-core/core-api/src/errors.rs +1 -34
- data/bridge/sdk-core/core-api/src/lib.rs +6 -2
- data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
- data/bridge/sdk-core/core-api/src/worker.rs +14 -1
- data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
- data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
- data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
- data/bridge/sdk-core/sdk/Cargo.toml +3 -2
- data/bridge/sdk-core/sdk/src/lib.rs +87 -20
- data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
- data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
- data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
- data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
- data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
- data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
- data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
- data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
- data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
- data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
- data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
- data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
- data/bridge/sdk-core/tests/main.rs +3 -13
- data/bridge/sdk-core/tests/runner.rs +75 -36
- data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
- data/bridge/src/connection.rs +41 -25
- data/bridge/src/lib.rs +269 -14
- data/bridge/src/runtime.rs +1 -1
- data/bridge/src/test_server.rs +153 -0
- data/bridge/src/worker.rs +89 -16
- data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
- data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
- data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
- data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
- data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
- data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
- data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
- data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
- data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
- data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
- data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
- data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
- data/lib/temporalio/activity/context.rb +13 -8
- data/lib/temporalio/activity/info.rb +1 -1
- data/lib/temporalio/bridge/connect_options.rb +15 -0
- data/lib/temporalio/bridge/retry_config.rb +24 -0
- data/lib/temporalio/bridge/tls_options.rb +19 -0
- data/lib/temporalio/client/implementation.rb +8 -8
- data/lib/temporalio/connection/retry_config.rb +44 -0
- data/lib/temporalio/connection/service.rb +20 -0
- data/lib/temporalio/connection/test_service.rb +92 -0
- data/lib/temporalio/connection/tls_options.rb +51 -0
- data/lib/temporalio/connection/workflow_service.rb +731 -0
- data/lib/temporalio/connection.rb +55 -720
- data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
- data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
- data/lib/temporalio/interceptor/chain.rb +5 -5
- data/lib/temporalio/interceptor/client.rb +8 -4
- data/lib/temporalio/interceptor.rb +22 -0
- data/lib/temporalio/retry_policy.rb +13 -3
- data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
- data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
- data/lib/temporalio/testing/workflow_environment.rb +112 -0
- data/lib/temporalio/testing.rb +175 -0
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/activity_runner.rb +26 -4
- data/lib/temporalio/worker/activity_worker.rb +44 -18
- data/lib/temporalio/worker/sync_worker.rb +47 -11
- data/lib/temporalio/worker.rb +27 -21
- data/lib/temporalio/workflow/async.rb +46 -0
- data/lib/temporalio/workflow/future.rb +138 -0
- data/lib/temporalio/workflow/info.rb +76 -0
- data/temporalio.gemspec +4 -3
- metadata +67 -17
- data/bridge/sdk-core/Cargo.lock +0 -2606
- data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
- data/lib/bridge.so +0 -0
- data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
- data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
- data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
@@ -1,22 +1,22 @@
|
|
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, RunBasics,
|
6
6
|
},
|
7
7
|
MetricsContext,
|
8
8
|
};
|
9
9
|
use lru::LruCache;
|
10
|
-
use std::{num::NonZeroUsize,
|
11
|
-
use
|
10
|
+
use std::{mem, num::NonZeroUsize, rc::Rc};
|
11
|
+
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::get_system_info_response;
|
12
12
|
|
13
13
|
pub(super) struct RunCache {
|
14
14
|
max: usize,
|
15
15
|
namespace: String,
|
16
|
-
|
16
|
+
server_capabilities: get_system_info_response::Capabilities,
|
17
17
|
/// Run id -> Data
|
18
|
-
runs: LruCache<String,
|
19
|
-
local_activity_request_sink: LocalActivityRequestSink
|
18
|
+
runs: LruCache<String, ManagedRun>,
|
19
|
+
local_activity_request_sink: Rc<dyn LocalActivityRequestSink>,
|
20
20
|
|
21
21
|
metrics: MetricsContext,
|
22
22
|
}
|
@@ -25,8 +25,8 @@ impl RunCache {
|
|
25
25
|
pub fn new(
|
26
26
|
max_cache_size: usize,
|
27
27
|
namespace: String,
|
28
|
-
|
29
|
-
local_activity_request_sink: LocalActivityRequestSink,
|
28
|
+
server_capabilities: get_system_info_response::Capabilities,
|
29
|
+
local_activity_request_sink: impl LocalActivityRequestSink,
|
30
30
|
metrics: MetricsContext,
|
31
31
|
) -> Self {
|
32
32
|
// The cache needs room for at least one run, otherwise we couldn't do anything. In
|
@@ -39,80 +39,63 @@ impl RunCache {
|
|
39
39
|
Self {
|
40
40
|
max: max_cache_size,
|
41
41
|
namespace,
|
42
|
-
|
42
|
+
server_capabilities,
|
43
43
|
runs: LruCache::new(
|
44
44
|
NonZeroUsize::new(lru_size).expect("LRU size is guaranteed positive"),
|
45
45
|
),
|
46
|
-
local_activity_request_sink,
|
46
|
+
local_activity_request_sink: Rc::new(local_activity_request_sink),
|
47
47
|
metrics,
|
48
48
|
}
|
49
49
|
}
|
50
50
|
|
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 {
|
51
|
+
pub fn instantiate_or_update(&mut self, mut pwft: PermittedWFT) -> RunUpdateAct {
|
59
52
|
let cur_num_cached_runs = self.runs.len();
|
53
|
+
let run_id = &pwft.work.execution.run_id;
|
60
54
|
|
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
|
-
});
|
55
|
+
if let Some(run_handle) = self.runs.get_mut(run_id) {
|
56
|
+
let rur = run_handle.incoming_wft(pwft);
|
72
57
|
self.metrics.cache_size(cur_num_cached_runs as u64);
|
73
|
-
return
|
58
|
+
return rur;
|
74
59
|
}
|
75
60
|
|
76
61
|
// Create a new workflow machines instance for this workflow, initialize it, and
|
77
62
|
// track it.
|
78
63
|
let metrics = self
|
79
64
|
.metrics
|
80
|
-
.with_new_attrs([workflow_type(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
65
|
+
.with_new_attrs([workflow_type(pwft.work.workflow_type.clone())]);
|
66
|
+
// Replace the update in the wft with a dummy one, since we must instantiate the machines
|
67
|
+
// with the update.
|
68
|
+
let history_update = mem::replace(&mut pwft.work.update, HistoryUpdate::dummy());
|
69
|
+
let mut mrh = ManagedRun::new(
|
70
|
+
RunBasics {
|
71
|
+
namespace: self.namespace.clone(),
|
72
|
+
workflow_id: pwft.work.execution.workflow_id.clone(),
|
73
|
+
workflow_type: pwft.work.workflow_type.clone(),
|
74
|
+
run_id: pwft.work.execution.run_id.clone(),
|
75
|
+
history: history_update,
|
76
|
+
metrics,
|
77
|
+
capabilities: &self.server_capabilities,
|
78
|
+
},
|
92
79
|
self.local_activity_request_sink.clone(),
|
93
|
-
metrics,
|
94
80
|
);
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
});
|
99
|
-
if self.runs.push(run_id.to_string(), mrh).is_some() {
|
81
|
+
let run_id = run_id.to_string();
|
82
|
+
let rur = mrh.incoming_wft(pwft);
|
83
|
+
if self.runs.push(run_id, mrh).is_some() {
|
100
84
|
panic!("Overflowed run cache! Cache owner is expected to avoid this!");
|
101
85
|
}
|
102
86
|
self.metrics.cache_size(cur_num_cached_runs as u64 + 1);
|
103
|
-
|
104
|
-
self.runs.get_mut(run_id).unwrap()
|
87
|
+
rur
|
105
88
|
}
|
106
|
-
pub fn remove(&mut self, k: &str) -> Option<
|
89
|
+
pub fn remove(&mut self, k: &str) -> Option<ManagedRun> {
|
107
90
|
let r = self.runs.pop(k);
|
108
91
|
self.metrics.cache_size(self.len() as u64);
|
109
92
|
r
|
110
93
|
}
|
111
94
|
|
112
|
-
pub fn get_mut(&mut self, k: &str) -> Option<&mut
|
95
|
+
pub fn get_mut(&mut self, k: &str) -> Option<&mut ManagedRun> {
|
113
96
|
self.runs.get_mut(k)
|
114
97
|
}
|
115
|
-
pub fn get(&mut self, k: &str) -> Option<&
|
98
|
+
pub fn get(&mut self, k: &str) -> Option<&ManagedRun> {
|
116
99
|
self.runs.get(k)
|
117
100
|
}
|
118
101
|
|
@@ -121,16 +104,16 @@ impl RunCache {
|
|
121
104
|
self.runs.peek_lru().map(|(run_id, _)| run_id.as_str())
|
122
105
|
}
|
123
106
|
/// Returns an iterator yielding cached runs in LRU order
|
124
|
-
pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &
|
107
|
+
pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &ManagedRun)> {
|
125
108
|
self.runs.iter().rev().map(|(k, v)| (k.as_str(), v))
|
126
109
|
}
|
127
|
-
pub fn peek(&self, k: &str) -> Option<&
|
110
|
+
pub fn peek(&self, k: &str) -> Option<&ManagedRun> {
|
128
111
|
self.runs.peek(k)
|
129
112
|
}
|
130
113
|
pub fn has_run(&self, k: &str) -> bool {
|
131
114
|
self.runs.contains(k)
|
132
115
|
}
|
133
|
-
pub fn handles(&self) -> impl Iterator<Item = &
|
116
|
+
pub fn handles(&self) -> impl Iterator<Item = &ManagedRun> {
|
134
117
|
self.runs.iter().map(|(_, v)| v)
|
135
118
|
}
|
136
119
|
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: permit.into_used(),
|
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,117 @@
|
|
1
|
+
use crate::{
|
2
|
+
telemetry::metrics::MetricsContext,
|
3
|
+
worker::{
|
4
|
+
client::mocks::DEFAULT_TEST_CAPABILITIES,
|
5
|
+
workflow::{
|
6
|
+
workflow_stream::{WFStream, WFStreamInput},
|
7
|
+
LAReqSink, LocalActivityRequestSink,
|
8
|
+
},
|
9
|
+
LocalActRequest, LocalActivityResolution,
|
10
|
+
},
|
11
|
+
};
|
12
|
+
use crossbeam::queue::SegQueue;
|
13
|
+
use futures::Stream;
|
14
|
+
use futures_util::StreamExt;
|
15
|
+
use serde::{Deserialize, Serialize};
|
16
|
+
use std::{future, sync::Arc};
|
17
|
+
use temporal_sdk_core_api::worker::WorkerConfig;
|
18
|
+
use tokio::sync::mpsc::UnboundedSender;
|
19
|
+
use tokio_util::sync::CancellationToken;
|
20
|
+
|
21
|
+
/// Replay everything that happened to internal workflow state. Useful for 100% deterministic
|
22
|
+
/// reproduction of bugs.
|
23
|
+
///
|
24
|
+
/// Use `CoreWfStarter::enable_wf_state_input_recording` from the integration test utilities to
|
25
|
+
/// activate saving the data to disk, and use the `wf_input_replay` example binary to replay.
|
26
|
+
pub async fn replay_wf_state_inputs(mut config: WorkerConfig, inputs: impl Stream<Item = Vec<u8>>) {
|
27
|
+
use crate::worker::build_wf_basics;
|
28
|
+
|
29
|
+
let la_resp_q = Arc::new(SegQueue::new());
|
30
|
+
let la_resp_q_clone = la_resp_q.clone();
|
31
|
+
let inputs = inputs
|
32
|
+
.map(|bytes| {
|
33
|
+
rmp_serde::from_slice::<StoredWFStateInputDeSer>(&bytes)
|
34
|
+
.expect("Can decode wf stream input")
|
35
|
+
})
|
36
|
+
.filter_map(|si| {
|
37
|
+
future::ready(match si {
|
38
|
+
StoredWFStateInputDeSer::Stream(wfsi) => Some(wfsi),
|
39
|
+
StoredWFStateInputDeSer::ImmediateLASinkResolutions(lares) => {
|
40
|
+
la_resp_q_clone.push(lares);
|
41
|
+
None
|
42
|
+
}
|
43
|
+
})
|
44
|
+
});
|
45
|
+
let basics = build_wf_basics(
|
46
|
+
&mut config,
|
47
|
+
MetricsContext::no_op(),
|
48
|
+
CancellationToken::new(),
|
49
|
+
DEFAULT_TEST_CAPABILITIES.clone(),
|
50
|
+
);
|
51
|
+
let sink = ReadingFromFileLaReqSink {
|
52
|
+
resolutions: la_resp_q,
|
53
|
+
};
|
54
|
+
info!("Beginning workflow stream internal state replay");
|
55
|
+
let stream = WFStream::build_internal(inputs, basics, sink);
|
56
|
+
stream
|
57
|
+
.for_each(|o| async move { trace!("Stream output: {:?}", o) })
|
58
|
+
.await;
|
59
|
+
}
|
60
|
+
|
61
|
+
impl WFStream {
|
62
|
+
pub(super) fn prep_input(&mut self, action: &WFStreamInput) -> Option<PreppedInputWrite> {
|
63
|
+
// Remove the channel, we'll put it back, avoiding a clone
|
64
|
+
self.wf_state_inputs.take().map(|chan| PreppedInputWrite {
|
65
|
+
data: rmp_serde::to_vec(&StoredWFStateInputSer::Stream(action))
|
66
|
+
.expect("WF Inputs are serializable"),
|
67
|
+
chan,
|
68
|
+
})
|
69
|
+
}
|
70
|
+
pub(super) fn flush_write(&mut self, w: PreppedInputWrite) {
|
71
|
+
let _ = w.chan.send(w.data);
|
72
|
+
self.wf_state_inputs = Some(w.chan);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
pub(super) struct PreppedInputWrite {
|
76
|
+
data: Vec<u8>,
|
77
|
+
chan: UnboundedSender<Vec<u8>>,
|
78
|
+
}
|
79
|
+
|
80
|
+
#[derive(Serialize)]
|
81
|
+
enum StoredWFStateInputSer<'a> {
|
82
|
+
Stream(&'a WFStreamInput),
|
83
|
+
ImmediateLASinkResolutions(&'a Vec<LocalActivityResolution>),
|
84
|
+
}
|
85
|
+
|
86
|
+
#[derive(Deserialize)]
|
87
|
+
enum StoredWFStateInputDeSer {
|
88
|
+
Stream(WFStreamInput),
|
89
|
+
ImmediateLASinkResolutions(Vec<LocalActivityResolution>),
|
90
|
+
}
|
91
|
+
|
92
|
+
struct ReadingFromFileLaReqSink {
|
93
|
+
resolutions: Arc<SegQueue<Vec<LocalActivityResolution>>>,
|
94
|
+
}
|
95
|
+
impl LocalActivityRequestSink for ReadingFromFileLaReqSink {
|
96
|
+
fn sink_reqs(&self, reqs: Vec<LocalActRequest>) -> Vec<LocalActivityResolution> {
|
97
|
+
if !reqs.is_empty() {
|
98
|
+
self.resolutions
|
99
|
+
.pop()
|
100
|
+
.expect("LA sink was called, but there's no stored immediate response")
|
101
|
+
} else {
|
102
|
+
vec![]
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
impl LAReqSink {
|
108
|
+
pub(crate) fn write_req(&self, res: &Vec<LocalActivityResolution>) {
|
109
|
+
if let Some(r) = self.recorder.as_ref() {
|
110
|
+
r.send(
|
111
|
+
rmp_serde::to_vec(&StoredWFStateInputSer::ImmediateLASinkResolutions(res))
|
112
|
+
.expect("LA immediate resolutions are serializable"),
|
113
|
+
)
|
114
|
+
.expect("WF input serialization channel is available for immediate LA result storage");
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
@@ -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
|
+
}
|