@temporalio/core-bridge 1.6.0 → 1.7.1
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 +520 -456
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +8 -3
- 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/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +1 -1
- package/sdk-core/.github/workflows/heavy.yml +1 -0
- package/sdk-core/README.md +13 -7
- package/sdk-core/client/src/lib.rs +27 -9
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +3 -3
- package/sdk-core/core/Cargo.toml +3 -4
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +197 -18
- package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +212 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
- package/sdk-core/core/src/core_tests/queries.rs +32 -14
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
- package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
- package/sdk-core/core/src/internal_flags.rs +141 -0
- package/sdk-core/core/src/lib.rs +14 -9
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +38 -14
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +65 -13
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
- package/sdk-core/core/src/worker/activities.rs +347 -173
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +137 -44
- package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
- package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
- package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
- package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
- package/sdk-core/core-api/Cargo.toml +0 -1
- package/sdk-core/core-api/src/lib.rs +13 -7
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +21 -5
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +9 -3
- package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
- package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/lib.rs +32 -5
- package/sdk-core/tests/heavy_tests.rs +10 -43
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
- package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
- package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
- package/sdk-core/tests/main.rs +16 -25
- package/sdk-core/tests/runner.rs +11 -9
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
|
@@ -23,6 +23,9 @@ use std::os::unix::fs::OpenOptionsExt;
|
|
|
23
23
|
use std::process::Stdio;
|
|
24
24
|
|
|
25
25
|
/// Configuration for Temporalite.
|
|
26
|
+
/// Will be removed eventually as its successor, Temporal CLI matures.
|
|
27
|
+
/// We don't care for the duplication between this struct and [TemporalDevServerConfig] and prefer that over another
|
|
28
|
+
/// abstraction since the existence of this struct is temporary.
|
|
26
29
|
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
27
30
|
pub struct TemporaliteConfig {
|
|
28
31
|
/// Required path to executable or download info.
|
|
@@ -59,7 +62,10 @@ impl TemporaliteConfig {
|
|
|
59
62
|
/// Start a Temporalite server with configurable stdout destination.
|
|
60
63
|
pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
|
|
61
64
|
// Get exe path
|
|
62
|
-
let exe_path = self
|
|
65
|
+
let exe_path = self
|
|
66
|
+
.exe
|
|
67
|
+
.get_or_download("temporalite", "temporalite", None)
|
|
68
|
+
.await?;
|
|
63
69
|
|
|
64
70
|
// Get free port if not already given
|
|
65
71
|
let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
|
|
@@ -77,6 +83,8 @@ impl TemporaliteConfig {
|
|
|
77
83
|
self.log.0.clone(),
|
|
78
84
|
"--log-level".to_owned(),
|
|
79
85
|
self.log.1.clone(),
|
|
86
|
+
"--dynamic-config-value".to_owned(),
|
|
87
|
+
"frontend.enableServerVersionCheck=false".to_owned(),
|
|
80
88
|
];
|
|
81
89
|
if let Some(db_filename) = &self.db_filename {
|
|
82
90
|
args.push("--filename".to_owned());
|
|
@@ -101,6 +109,89 @@ impl TemporaliteConfig {
|
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
111
|
|
|
112
|
+
/// Configuration for Temporal CLI dev server.
|
|
113
|
+
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
114
|
+
pub struct TemporalDevServerConfig {
|
|
115
|
+
/// Required path to executable or download info.
|
|
116
|
+
pub exe: EphemeralExe,
|
|
117
|
+
/// Namespace to use.
|
|
118
|
+
#[builder(default = "\"default\".to_owned()")]
|
|
119
|
+
pub namespace: String,
|
|
120
|
+
/// IP to bind to.
|
|
121
|
+
#[builder(default = "\"127.0.0.1\".to_owned()")]
|
|
122
|
+
pub ip: String,
|
|
123
|
+
/// Port to use or obtains a free one if none given.
|
|
124
|
+
#[builder(default)]
|
|
125
|
+
pub port: Option<u16>,
|
|
126
|
+
/// Sqlite DB filename if persisting or non-persistent if none.
|
|
127
|
+
#[builder(default)]
|
|
128
|
+
pub db_filename: Option<String>,
|
|
129
|
+
/// Whether to enable the UI.
|
|
130
|
+
#[builder(default)]
|
|
131
|
+
pub ui: bool,
|
|
132
|
+
/// Log format and level
|
|
133
|
+
#[builder(default = "(\"pretty\".to_owned(), \"warn\".to_owned())")]
|
|
134
|
+
pub log: (String, String),
|
|
135
|
+
/// Additional arguments to Temporalite.
|
|
136
|
+
#[builder(default)]
|
|
137
|
+
pub extra_args: Vec<String>,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
impl TemporalDevServerConfig {
|
|
141
|
+
/// Start a Temporal CLI dev server.
|
|
142
|
+
pub async fn start_server(&self) -> anyhow::Result<EphemeralServer> {
|
|
143
|
+
self.start_server_with_output(Stdio::inherit()).await
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Start a Temporal CLI dev server with configurable stdout destination.
|
|
147
|
+
pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
|
|
148
|
+
// Get exe path
|
|
149
|
+
let exe_path = self
|
|
150
|
+
.exe
|
|
151
|
+
.get_or_download("cli", "temporal", Some("tar.gz"))
|
|
152
|
+
.await?;
|
|
153
|
+
|
|
154
|
+
// Get free port if not already given
|
|
155
|
+
let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
|
|
156
|
+
|
|
157
|
+
// Build arg set
|
|
158
|
+
let mut args = vec![
|
|
159
|
+
"server".to_owned(),
|
|
160
|
+
"start-dev".to_owned(),
|
|
161
|
+
"--port".to_owned(),
|
|
162
|
+
port.to_string(),
|
|
163
|
+
"--namespace".to_owned(),
|
|
164
|
+
self.namespace.clone(),
|
|
165
|
+
"--ip".to_owned(),
|
|
166
|
+
self.ip.clone(),
|
|
167
|
+
"--log-format".to_owned(),
|
|
168
|
+
self.log.0.clone(),
|
|
169
|
+
"--log-level".to_owned(),
|
|
170
|
+
self.log.1.clone(),
|
|
171
|
+
"--dynamic-config-value".to_owned(),
|
|
172
|
+
"frontend.enableServerVersionCheck=false".to_owned(),
|
|
173
|
+
];
|
|
174
|
+
if let Some(db_filename) = &self.db_filename {
|
|
175
|
+
args.push("--filename".to_owned());
|
|
176
|
+
args.push(db_filename.clone());
|
|
177
|
+
}
|
|
178
|
+
if !self.ui {
|
|
179
|
+
args.push("--headless".to_owned());
|
|
180
|
+
}
|
|
181
|
+
args.extend(self.extra_args.clone());
|
|
182
|
+
|
|
183
|
+
// Start
|
|
184
|
+
EphemeralServer::start(EphemeralServerConfig {
|
|
185
|
+
exe_path,
|
|
186
|
+
port,
|
|
187
|
+
args,
|
|
188
|
+
has_test_service: false,
|
|
189
|
+
output,
|
|
190
|
+
})
|
|
191
|
+
.await
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
104
195
|
/// Configuration for the test server.
|
|
105
196
|
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
106
197
|
pub struct TestServerConfig {
|
|
@@ -123,7 +214,10 @@ impl TestServerConfig {
|
|
|
123
214
|
/// Start a test server with configurable stdout.
|
|
124
215
|
pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
|
|
125
216
|
// Get exe path
|
|
126
|
-
let exe_path = self
|
|
217
|
+
let exe_path = self
|
|
218
|
+
.exe
|
|
219
|
+
.get_or_download("temporal-test-server", "temporal-test-server", None)
|
|
220
|
+
.await?;
|
|
127
221
|
|
|
128
222
|
// Get free port if not already given
|
|
129
223
|
let port = self.port.unwrap_or_else(|| get_free_port("0.0.0.0"));
|
|
@@ -262,7 +356,7 @@ pub enum EphemeralExe {
|
|
|
262
356
|
#[derive(Debug, Clone)]
|
|
263
357
|
pub enum EphemeralExeVersion {
|
|
264
358
|
/// Use a default version for the given SDK name and version.
|
|
265
|
-
|
|
359
|
+
SDKDefault {
|
|
266
360
|
/// Name of the SDK to get the default for.
|
|
267
361
|
sdk_name: String,
|
|
268
362
|
/// Version of the SDK to get the default for.
|
|
@@ -280,7 +374,12 @@ struct DownloadInfo {
|
|
|
280
374
|
}
|
|
281
375
|
|
|
282
376
|
impl EphemeralExe {
|
|
283
|
-
async fn get_or_download(
|
|
377
|
+
async fn get_or_download(
|
|
378
|
+
&self,
|
|
379
|
+
artifact_name: &str,
|
|
380
|
+
downloaded_name_prefix: &str,
|
|
381
|
+
preferred_format: Option<&str>,
|
|
382
|
+
) -> anyhow::Result<PathBuf> {
|
|
284
383
|
match self {
|
|
285
384
|
EphemeralExe::ExistingPath(exe_path) => {
|
|
286
385
|
let path = PathBuf::from(exe_path);
|
|
@@ -301,12 +400,12 @@ impl EphemeralExe {
|
|
|
301
400
|
};
|
|
302
401
|
// Create dest file based on SDK name/version or fixed version
|
|
303
402
|
let dest = dest_dir.join(match version {
|
|
304
|
-
EphemeralExeVersion::
|
|
403
|
+
EphemeralExeVersion::SDKDefault {
|
|
305
404
|
sdk_name,
|
|
306
405
|
sdk_version,
|
|
307
|
-
} => format!("{
|
|
406
|
+
} => format!("{downloaded_name_prefix}-{sdk_name}-{sdk_version}{out_ext}"),
|
|
308
407
|
EphemeralExeVersion::Fixed(version) => {
|
|
309
|
-
format!("{
|
|
408
|
+
format!("{downloaded_name_prefix}-{version}{out_ext}")
|
|
310
409
|
}
|
|
311
410
|
});
|
|
312
411
|
debug!(
|
|
@@ -326,8 +425,11 @@ impl EphemeralExe {
|
|
|
326
425
|
other => return Err(anyhow!("Unsupported arch: {}", other)),
|
|
327
426
|
};
|
|
328
427
|
let mut get_info_params = vec![("arch", arch), ("platform", platform)];
|
|
428
|
+
if let Some(format) = preferred_format {
|
|
429
|
+
get_info_params.push(("format", format));
|
|
430
|
+
}
|
|
329
431
|
let version_name = match version {
|
|
330
|
-
EphemeralExeVersion::
|
|
432
|
+
EphemeralExeVersion::SDKDefault {
|
|
331
433
|
sdk_name,
|
|
332
434
|
sdk_version,
|
|
333
435
|
} => {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
//! Utilities for and tracking of internal versions which alter history in incompatible ways
|
|
2
|
+
//! so that we can use older code paths for workflows executed on older core versions.
|
|
3
|
+
|
|
4
|
+
use std::collections::{BTreeSet, HashSet};
|
|
5
|
+
use temporal_sdk_core_protos::temporal::api::{
|
|
6
|
+
history::v1::WorkflowTaskCompletedEventAttributes, sdk::v1::WorkflowTaskCompletedMetadata,
|
|
7
|
+
workflowservice::v1::get_system_info_response,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/// This enumeration contains internal flags that may result in incompatible history changes with
|
|
11
|
+
/// older workflows, or other breaking changes.
|
|
12
|
+
///
|
|
13
|
+
/// When a flag has existed long enough the version it was introduced in is no longer supported, it
|
|
14
|
+
/// may be removed from the enum. *Importantly*, all variants must be given explicit values, such
|
|
15
|
+
/// that removing older variants does not create any change in existing values. Removed flag
|
|
16
|
+
/// variants must be reserved forever (a-la protobuf), and should be called out in a comment.
|
|
17
|
+
#[repr(u32)]
|
|
18
|
+
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
|
|
19
|
+
pub(crate) enum CoreInternalFlags {
|
|
20
|
+
/// In this flag additional checks were added to a number of state machines to ensure that
|
|
21
|
+
/// the ID and type of activities, local activities, and child workflows match during replay.
|
|
22
|
+
IdAndTypeDeterminismChecks = 1,
|
|
23
|
+
/// Introduced automatically upserting search attributes for each patched call, and
|
|
24
|
+
/// nondeterminism checks for upserts.
|
|
25
|
+
UpsertSearchAttributeOnPatch = 2,
|
|
26
|
+
/// We received a value higher than this code can understand.
|
|
27
|
+
TooHigh = u32::MAX,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
31
|
+
pub(crate) struct InternalFlags {
|
|
32
|
+
enabled: bool,
|
|
33
|
+
core: BTreeSet<CoreInternalFlags>,
|
|
34
|
+
lang: BTreeSet<u32>,
|
|
35
|
+
core_since_last_complete: HashSet<CoreInternalFlags>,
|
|
36
|
+
lang_since_last_complete: HashSet<u32>,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl InternalFlags {
|
|
40
|
+
pub fn new(server_capabilities: &get_system_info_response::Capabilities) -> Self {
|
|
41
|
+
Self {
|
|
42
|
+
enabled: server_capabilities.sdk_metadata,
|
|
43
|
+
core: Default::default(),
|
|
44
|
+
lang: Default::default(),
|
|
45
|
+
core_since_last_complete: Default::default(),
|
|
46
|
+
lang_since_last_complete: Default::default(),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pub fn add_from_complete(&mut self, e: &WorkflowTaskCompletedEventAttributes) {
|
|
51
|
+
if !self.enabled {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if let Some(metadata) = e.sdk_metadata.as_ref() {
|
|
56
|
+
self.core.extend(
|
|
57
|
+
metadata
|
|
58
|
+
.core_used_flags
|
|
59
|
+
.iter()
|
|
60
|
+
.map(|u| CoreInternalFlags::from_u32(*u)),
|
|
61
|
+
);
|
|
62
|
+
self.lang.extend(metadata.lang_used_flags.iter());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub fn add_lang_used(&mut self, flags: impl IntoIterator<Item = u32>) {
|
|
67
|
+
if !self.enabled {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
self.lang_since_last_complete.extend(flags.into_iter());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// Returns true if this flag may currently be used. If `should_record` is true, always returns
|
|
75
|
+
/// true and records the flag as being used, for taking later via
|
|
76
|
+
/// [Self::gather_for_wft_complete].
|
|
77
|
+
pub fn try_use(&mut self, core_patch: CoreInternalFlags, should_record: bool) -> bool {
|
|
78
|
+
if !self.enabled {
|
|
79
|
+
// If the server does not support the metadata field, we must assume we can never use
|
|
80
|
+
// any internal flags since they can't be recorded for future use
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if should_record {
|
|
85
|
+
self.core_since_last_complete.insert(core_patch);
|
|
86
|
+
true
|
|
87
|
+
} else {
|
|
88
|
+
self.core.contains(&core_patch)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Wipes the recorded flags used during the current WFT and returns a partially filled
|
|
93
|
+
/// sdk metadata message that can be combined with any existing data before sending the WFT
|
|
94
|
+
/// complete
|
|
95
|
+
pub fn gather_for_wft_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
96
|
+
WorkflowTaskCompletedMetadata {
|
|
97
|
+
core_used_flags: self
|
|
98
|
+
.core_since_last_complete
|
|
99
|
+
.drain()
|
|
100
|
+
.map(|p| p as u32)
|
|
101
|
+
.collect(),
|
|
102
|
+
lang_used_flags: self.lang_since_last_complete.drain().collect(),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub fn all_lang(&self) -> &BTreeSet<u32> {
|
|
107
|
+
&self.lang
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
impl CoreInternalFlags {
|
|
112
|
+
fn from_u32(v: u32) -> Self {
|
|
113
|
+
match v {
|
|
114
|
+
1 => Self::IdAndTypeDeterminismChecks,
|
|
115
|
+
2 => Self::UpsertSearchAttributeOnPatch,
|
|
116
|
+
_ => Self::TooHigh,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#[cfg(test)]
|
|
122
|
+
mod tests {
|
|
123
|
+
use super::*;
|
|
124
|
+
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::get_system_info_response::Capabilities;
|
|
125
|
+
|
|
126
|
+
#[test]
|
|
127
|
+
fn disabled_in_capabilities_disables() {
|
|
128
|
+
let mut f = InternalFlags::new(&Capabilities::default());
|
|
129
|
+
f.add_lang_used([1]);
|
|
130
|
+
f.add_from_complete(&WorkflowTaskCompletedEventAttributes {
|
|
131
|
+
sdk_metadata: Some(WorkflowTaskCompletedMetadata {
|
|
132
|
+
core_used_flags: vec![1],
|
|
133
|
+
lang_used_flags: vec![],
|
|
134
|
+
}),
|
|
135
|
+
..Default::default()
|
|
136
|
+
});
|
|
137
|
+
let gathered = f.gather_for_wft_complete();
|
|
138
|
+
assert_matches!(gathered.core_used_flags.as_slice(), &[]);
|
|
139
|
+
assert_matches!(gathered.lang_used_flags.as_slice(), &[]);
|
|
140
|
+
}
|
|
141
|
+
}
|
package/sdk-core/core/src/lib.rs
CHANGED
|
@@ -13,6 +13,7 @@ extern crate core;
|
|
|
13
13
|
|
|
14
14
|
mod abstractions;
|
|
15
15
|
pub mod ephemeral_server;
|
|
16
|
+
mod internal_flags;
|
|
16
17
|
mod pollers;
|
|
17
18
|
mod protosext;
|
|
18
19
|
pub mod replay;
|
|
@@ -43,8 +44,9 @@ pub use worker::{Worker, WorkerConfig, WorkerConfigBuilder};
|
|
|
43
44
|
use crate::{
|
|
44
45
|
replay::{mock_client_from_histories, Historator, HistoryForReplay},
|
|
45
46
|
telemetry::{
|
|
46
|
-
metrics::MetricsContext,
|
|
47
|
-
|
|
47
|
+
metrics::{MetricsContext, TemporalMeter},
|
|
48
|
+
remove_trace_subscriber_for_current_thread, set_trace_subscriber_for_current_thread,
|
|
49
|
+
telemetry_init, TelemetryInstance,
|
|
48
50
|
},
|
|
49
51
|
worker::client::WorkerClientBag,
|
|
50
52
|
};
|
|
@@ -53,7 +55,7 @@ use std::sync::Arc;
|
|
|
53
55
|
use temporal_client::{ConfiguredClient, TemporalServiceClientWithMetrics};
|
|
54
56
|
use temporal_sdk_core_api::{
|
|
55
57
|
errors::{CompleteActivityError, PollActivityError, PollWfError},
|
|
56
|
-
telemetry::
|
|
58
|
+
telemetry::TelemetryOptions,
|
|
57
59
|
Worker as WorkerTrait,
|
|
58
60
|
};
|
|
59
61
|
use temporal_sdk_core_protos::coresdk::ActivityHeartbeat;
|
|
@@ -64,7 +66,7 @@ use temporal_sdk_core_protos::coresdk::ActivityHeartbeat;
|
|
|
64
66
|
/// After the worker is initialized, you should use [CoreRuntime::tokio_handle] to run the worker's
|
|
65
67
|
/// async functions.
|
|
66
68
|
///
|
|
67
|
-
/// Lang implementations may pass in a [
|
|
69
|
+
/// Lang implementations may pass in a [ConfiguredClient] directly (or a
|
|
68
70
|
/// [RetryClient] wrapping one, or a handful of other variants of the same idea). When they do so,
|
|
69
71
|
/// this function will always overwrite the client retry configuration, force the client to use the
|
|
70
72
|
/// namespace defined in the worker config, and set the client identity appropriately. IE: Use
|
|
@@ -99,9 +101,12 @@ where
|
|
|
99
101
|
worker_config.use_worker_versioning,
|
|
100
102
|
));
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
Ok(Worker::new(
|
|
105
|
+
worker_config,
|
|
106
|
+
sticky_q,
|
|
107
|
+
client_bag,
|
|
108
|
+
Some(&runtime.telemetry),
|
|
109
|
+
))
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
/// Create a worker for replaying a specific history. It will auto-shutdown as soon as the history
|
|
@@ -128,7 +133,7 @@ where
|
|
|
128
133
|
let post_activate = historator.get_post_activate_hook();
|
|
129
134
|
let shutdown_tok = historator.get_shutdown_setter();
|
|
130
135
|
let client = mock_client_from_histories(historator);
|
|
131
|
-
let mut worker = Worker::new(config, None, Arc::new(client),
|
|
136
|
+
let mut worker = Worker::new(config, None, Arc::new(client), None);
|
|
132
137
|
worker.set_post_activate_hook(post_activate);
|
|
133
138
|
shutdown_tok(worker.shutdown_token());
|
|
134
139
|
Ok(worker)
|
|
@@ -260,7 +265,7 @@ impl CoreRuntime {
|
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
/// Returns the metric meter used for recording metrics, if they were enabled.
|
|
263
|
-
pub fn metric_meter(&self) -> Option
|
|
268
|
+
pub fn metric_meter(&self) -> Option<TemporalMeter> {
|
|
264
269
|
self.telemetry.get_metric_meter()
|
|
265
270
|
}
|
|
266
271
|
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
//! users during testing.
|
|
4
4
|
|
|
5
5
|
use crate::{
|
|
6
|
-
worker::
|
|
6
|
+
worker::{
|
|
7
|
+
client::{mocks::mock_manual_workflow_client, WorkerClient},
|
|
8
|
+
PostActivateHookData,
|
|
9
|
+
},
|
|
7
10
|
Worker,
|
|
8
11
|
};
|
|
9
12
|
use futures::{FutureExt, Stream, StreamExt};
|
|
10
13
|
use once_cell::sync::OnceCell;
|
|
11
14
|
use parking_lot::Mutex;
|
|
12
15
|
use std::{
|
|
13
|
-
collections::HashMap,
|
|
14
16
|
pin::Pin,
|
|
15
17
|
sync::Arc,
|
|
16
18
|
task::{Context, Poll},
|
|
@@ -147,25 +149,18 @@ impl Historator {
|
|
|
147
149
|
|
|
148
150
|
/// Returns a callback that can be used as the post-activation hook for a worker to indicate
|
|
149
151
|
/// we're ready to replay the next history, or whatever else.
|
|
150
|
-
pub(crate) fn get_post_activate_hook(
|
|
151
|
-
|
|
152
|
+
pub(crate) fn get_post_activate_hook(
|
|
153
|
+
&self,
|
|
154
|
+
) -> impl Fn(&Worker, PostActivateHookData) + Send + Sync {
|
|
152
155
|
let done_tx = self.replay_done_tx.clone();
|
|
153
|
-
move |worker,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if last_processed_event >= le {
|
|
162
|
-
worker.request_wf_eviction(
|
|
163
|
-
activated_run_id,
|
|
164
|
-
"Always evict workflows after replay",
|
|
165
|
-
EvictionReason::LangRequested,
|
|
166
|
-
);
|
|
167
|
-
done_tx.send(activated_run_id.to_string()).unwrap();
|
|
168
|
-
}
|
|
156
|
+
move |worker, data| {
|
|
157
|
+
if !data.replaying {
|
|
158
|
+
worker.request_wf_eviction(
|
|
159
|
+
data.run_id,
|
|
160
|
+
"Always evict workflows after replay",
|
|
161
|
+
EvictionReason::LangRequested,
|
|
162
|
+
);
|
|
163
|
+
done_tx.send(data.run_id.to_string()).unwrap();
|
|
169
164
|
}
|
|
170
165
|
}
|
|
171
166
|
}
|
|
@@ -184,7 +179,7 @@ impl Stream for Historator {
|
|
|
184
179
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
185
180
|
match self.iter.poll_next_unpin(cx) {
|
|
186
181
|
Poll::Ready(Some(history)) => {
|
|
187
|
-
|
|
182
|
+
history
|
|
188
183
|
.hist
|
|
189
184
|
.extract_run_id_from_start()
|
|
190
185
|
.expect(
|
|
@@ -192,11 +187,6 @@ impl Stream for Historator {
|
|
|
192
187
|
execution started events",
|
|
193
188
|
)
|
|
194
189
|
.to_string();
|
|
195
|
-
let last_event = history.hist.last_event_id();
|
|
196
|
-
self.dat
|
|
197
|
-
.lock()
|
|
198
|
-
.run_id_to_last_event_num
|
|
199
|
-
.insert(run_id, last_event as usize);
|
|
200
190
|
Poll::Ready(Some(history))
|
|
201
191
|
}
|
|
202
192
|
Poll::Ready(None) => {
|
|
@@ -210,6 +200,5 @@ impl Stream for Historator {
|
|
|
210
200
|
|
|
211
201
|
#[derive(Default)]
|
|
212
202
|
struct HistoratorDat {
|
|
213
|
-
run_id_to_last_event_num: HashMap<String, usize>,
|
|
214
203
|
all_dispatched: bool,
|
|
215
204
|
}
|
|
@@ -10,8 +10,8 @@ use opentelemetry::{
|
|
|
10
10
|
},
|
|
11
11
|
Context, KeyValue,
|
|
12
12
|
};
|
|
13
|
-
use std::{sync::Arc, time::Duration};
|
|
14
|
-
use
|
|
13
|
+
use std::{ops::Deref, sync::Arc, time::Duration};
|
|
14
|
+
use temporal_client::ClientMetricProvider;
|
|
15
15
|
|
|
16
16
|
/// Used to track context associated with metrics, and record/update them
|
|
17
17
|
///
|
|
@@ -24,6 +24,46 @@ pub(crate) struct MetricsContext {
|
|
|
24
24
|
instruments: Arc<Instruments>,
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/// Wraps OTel's [Meter] to ensure we name our metrics properly, or any other temporal-specific
|
|
28
|
+
/// metrics customizations
|
|
29
|
+
#[derive(derive_more::Constructor)]
|
|
30
|
+
pub struct TemporalMeter<'a> {
|
|
31
|
+
inner: &'a Meter,
|
|
32
|
+
metrics_prefix: &'static str,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl<'a> TemporalMeter<'a> {
|
|
36
|
+
pub(crate) fn counter(&self, name: &'static str) -> Counter<u64> {
|
|
37
|
+
self.inner
|
|
38
|
+
.u64_counter(self.metrics_prefix.to_string() + name)
|
|
39
|
+
.init()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pub(crate) fn histogram(&self, name: &'static str) -> Histogram<u64> {
|
|
43
|
+
self.inner
|
|
44
|
+
.u64_histogram(self.metrics_prefix.to_string() + name)
|
|
45
|
+
.init()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
impl<'a> ClientMetricProvider for TemporalMeter<'a> {
|
|
50
|
+
fn counter(&self, name: &'static str) -> Counter<u64> {
|
|
51
|
+
self.counter(name)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fn histogram(&self, name: &'static str) -> Histogram<u64> {
|
|
55
|
+
self.histogram(name)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
impl<'a> Deref for TemporalMeter<'a> {
|
|
60
|
+
type Target = dyn ClientMetricProvider + 'a;
|
|
61
|
+
|
|
62
|
+
fn deref(&self) -> &Self::Target {
|
|
63
|
+
self as &Self::Target
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
27
67
|
struct Instruments {
|
|
28
68
|
wf_completed_counter: Counter<u64>,
|
|
29
69
|
wf_canceled_counter: Counter<u64>,
|
|
@@ -54,10 +94,10 @@ impl MetricsContext {
|
|
|
54
94
|
Self {
|
|
55
95
|
ctx: Default::default(),
|
|
56
96
|
kvs: Default::default(),
|
|
57
|
-
instruments: Arc::new(Instruments::new_explicit(
|
|
97
|
+
instruments: Arc::new(Instruments::new_explicit(TemporalMeter::new(
|
|
58
98
|
&NoopMeterProvider::new().meter("fakemeter"),
|
|
59
99
|
"fakemetrics",
|
|
60
|
-
)),
|
|
100
|
+
))),
|
|
61
101
|
}
|
|
62
102
|
}
|
|
63
103
|
|
|
@@ -257,42 +297,36 @@ impl Instruments {
|
|
|
257
297
|
meter
|
|
258
298
|
} else {
|
|
259
299
|
no_op_meter = NoopMeterProvider::default().meter("no_op");
|
|
260
|
-
&no_op_meter
|
|
300
|
+
TemporalMeter::new(&no_op_meter, "fakemetrics")
|
|
261
301
|
};
|
|
262
|
-
Self::new_explicit(meter
|
|
302
|
+
Self::new_explicit(meter)
|
|
263
303
|
}
|
|
264
304
|
|
|
265
|
-
fn new_explicit(meter:
|
|
266
|
-
let ctr = |name: &'static str| -> Counter<u64> {
|
|
267
|
-
meter.u64_counter(metric_prefix.to_string() + name).init()
|
|
268
|
-
};
|
|
269
|
-
let hst = |name: &'static str| -> Histogram<u64> {
|
|
270
|
-
meter.u64_histogram(metric_prefix.to_string() + name).init()
|
|
271
|
-
};
|
|
305
|
+
fn new_explicit(meter: TemporalMeter) -> Self {
|
|
272
306
|
Self {
|
|
273
|
-
wf_completed_counter:
|
|
274
|
-
wf_canceled_counter:
|
|
275
|
-
wf_failed_counter:
|
|
276
|
-
wf_cont_counter:
|
|
277
|
-
wf_e2e_latency:
|
|
278
|
-
wf_task_queue_poll_empty_counter:
|
|
279
|
-
wf_task_queue_poll_succeed_counter:
|
|
280
|
-
wf_task_execution_failure_counter:
|
|
281
|
-
wf_task_sched_to_start_latency:
|
|
282
|
-
wf_task_replay_latency:
|
|
283
|
-
wf_task_execution_latency:
|
|
284
|
-
act_poll_no_task:
|
|
285
|
-
act_task_received_counter:
|
|
286
|
-
act_execution_failed:
|
|
287
|
-
act_sched_to_start_latency:
|
|
288
|
-
act_exec_latency:
|
|
307
|
+
wf_completed_counter: meter.counter("workflow_completed"),
|
|
308
|
+
wf_canceled_counter: meter.counter("workflow_canceled"),
|
|
309
|
+
wf_failed_counter: meter.counter("workflow_failed"),
|
|
310
|
+
wf_cont_counter: meter.counter("workflow_continue_as_new"),
|
|
311
|
+
wf_e2e_latency: meter.histogram(WF_E2E_LATENCY_NAME),
|
|
312
|
+
wf_task_queue_poll_empty_counter: meter.counter("workflow_task_queue_poll_empty"),
|
|
313
|
+
wf_task_queue_poll_succeed_counter: meter.counter("workflow_task_queue_poll_succeed"),
|
|
314
|
+
wf_task_execution_failure_counter: meter.counter("workflow_task_execution_failed"),
|
|
315
|
+
wf_task_sched_to_start_latency: meter.histogram(WF_TASK_SCHED_TO_START_LATENCY_NAME),
|
|
316
|
+
wf_task_replay_latency: meter.histogram(WF_TASK_REPLAY_LATENCY_NAME),
|
|
317
|
+
wf_task_execution_latency: meter.histogram(WF_TASK_EXECUTION_LATENCY_NAME),
|
|
318
|
+
act_poll_no_task: meter.counter("activity_poll_no_task"),
|
|
319
|
+
act_task_received_counter: meter.counter("activity_task_received"),
|
|
320
|
+
act_execution_failed: meter.counter("activity_execution_failed"),
|
|
321
|
+
act_sched_to_start_latency: meter.histogram(ACT_SCHED_TO_START_LATENCY_NAME),
|
|
322
|
+
act_exec_latency: meter.histogram(ACT_EXEC_LATENCY_NAME),
|
|
289
323
|
// name kept as worker start for compat with old sdk / what users expect
|
|
290
|
-
worker_registered:
|
|
291
|
-
num_pollers:
|
|
292
|
-
task_slots_available:
|
|
293
|
-
sticky_cache_hit:
|
|
294
|
-
sticky_cache_miss:
|
|
295
|
-
sticky_cache_size:
|
|
324
|
+
worker_registered: meter.counter("worker_start"),
|
|
325
|
+
num_pollers: meter.histogram(NUM_POLLERS_NAME),
|
|
326
|
+
task_slots_available: meter.histogram(TASK_SLOTS_AVAILABLE_NAME),
|
|
327
|
+
sticky_cache_hit: meter.counter("sticky_cache_hit"),
|
|
328
|
+
sticky_cache_miss: meter.counter("sticky_cache_miss"),
|
|
329
|
+
sticky_cache_size: meter.histogram(STICKY_CACHE_SIZE_NAME),
|
|
296
330
|
}
|
|
297
331
|
}
|
|
298
332
|
}
|