@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.
Files changed (138) hide show
  1. package/Cargo.lock +520 -456
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +8 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +1 -1
  13. package/sdk-core/.github/workflows/heavy.yml +1 -0
  14. package/sdk-core/README.md +13 -7
  15. package/sdk-core/client/src/lib.rs +27 -9
  16. package/sdk-core/client/src/metrics.rs +17 -8
  17. package/sdk-core/client/src/raw.rs +3 -3
  18. package/sdk-core/core/Cargo.toml +3 -4
  19. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  20. package/sdk-core/core/src/abstractions.rs +197 -18
  21. package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
  22. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  23. package/sdk-core/core/src/core_tests/determinism.rs +212 -2
  24. package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
  25. package/sdk-core/core/src/core_tests/queries.rs +32 -14
  26. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  27. package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
  28. package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
  29. package/sdk-core/core/src/internal_flags.rs +141 -0
  30. package/sdk-core/core/src/lib.rs +14 -9
  31. package/sdk-core/core/src/replay/mod.rs +16 -27
  32. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  33. package/sdk-core/core/src/telemetry/mod.rs +38 -14
  34. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  35. package/sdk-core/core/src/test_help/mod.rs +65 -13
  36. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  37. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  38. package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
  39. package/sdk-core/core/src/worker/activities.rs +347 -173
  40. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  41. package/sdk-core/core/src/worker/client.rs +18 -2
  42. package/sdk-core/core/src/worker/mod.rs +137 -44
  43. package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
  44. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
  45. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
  46. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
  47. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
  48. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
  49. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
  50. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
  51. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
  52. package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
  53. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
  54. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
  55. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
  56. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
  57. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
  58. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
  59. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
  60. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
  61. package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
  62. package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
  63. package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
  64. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
  65. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
  66. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
  67. package/sdk-core/core-api/Cargo.toml +0 -1
  68. package/sdk-core/core-api/src/lib.rs +13 -7
  69. package/sdk-core/core-api/src/telemetry.rs +4 -6
  70. package/sdk-core/core-api/src/worker.rs +5 -0
  71. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
  72. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
  73. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  74. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  75. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  76. package/sdk-core/protos/api_upstream/Makefile +1 -1
  77. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  78. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  80. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  81. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  83. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  84. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  85. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  86. package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  87. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  88. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  89. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  90. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  91. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  92. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  93. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  94. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  95. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  96. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  97. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
  98. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  99. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  100. package/sdk-core/sdk/Cargo.toml +1 -1
  101. package/sdk-core/sdk/src/lib.rs +21 -5
  102. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  103. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  104. package/sdk-core/sdk/src/workflow_future.rs +9 -3
  105. package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
  106. package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
  107. package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
  108. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  109. package/sdk-core/test-utils/src/lib.rs +32 -5
  110. package/sdk-core/tests/heavy_tests.rs +10 -43
  111. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
  115. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
  116. package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
  117. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
  118. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
  120. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  121. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
  122. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
  123. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
  124. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  125. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
  126. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
  127. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
  129. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
  130. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
  131. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
  132. package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
  133. package/sdk-core/tests/main.rs +16 -25
  134. package/sdk-core/tests/runner.rs +11 -9
  135. package/src/conversions.rs +14 -8
  136. package/src/runtime.rs +9 -8
  137. package/ts/index.ts +8 -6
  138. 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.exe.get_or_download("temporalite").await?;
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.exe.get_or_download("temporal-test-server").await?;
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
- Default {
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(&self, artifact_name: &str) -> anyhow::Result<PathBuf> {
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::Default {
403
+ EphemeralExeVersion::SDKDefault {
305
404
  sdk_name,
306
405
  sdk_version,
307
- } => format!("{artifact_name}-{sdk_name}-{sdk_version}{out_ext}"),
406
+ } => format!("{downloaded_name_prefix}-{sdk_name}-{sdk_version}{out_ext}"),
308
407
  EphemeralExeVersion::Fixed(version) => {
309
- format!("{artifact_name}-{version}{out_ext}")
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::Default {
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
+ }
@@ -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, remove_trace_subscriber_for_current_thread,
47
- set_trace_subscriber_for_current_thread, telemetry_init, TelemetryInstance,
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::{CoreTelemetry, TelemetryOptions},
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 [temporal_client::ConfiguredClient] directly (or 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
- let metrics = MetricsContext::top_level(worker_config.namespace.clone(), &runtime.telemetry)
103
- .with_task_q(worker_config.task_queue.clone());
104
- Ok(Worker::new(worker_config, sticky_q, client_bag, metrics))
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), MetricsContext::no_op());
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<&opentelemetry::metrics::Meter> {
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::client::{mocks::mock_manual_workflow_client, WorkerClient},
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(&self) -> impl Fn(&Worker, &str, usize) + Send + Sync {
151
- let dat = self.dat.clone();
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, activated_run_id, last_processed_event| {
154
- // We can't hold the lock while evaluating the hook, or we'd deadlock.
155
- let last_event_in_hist = dat
156
- .lock()
157
- .run_id_to_last_event_num
158
- .get(activated_run_id)
159
- .cloned();
160
- if let Some(le) = last_event_in_hist {
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
- let run_id = history
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 temporal_sdk_core_api::telemetry::CoreTelemetry;
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, telem.metric_prefix)
302
+ Self::new_explicit(meter)
263
303
  }
264
304
 
265
- fn new_explicit(meter: &Meter, metric_prefix: &'static str) -> Self {
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: ctr("workflow_completed"),
274
- wf_canceled_counter: ctr("workflow_canceled"),
275
- wf_failed_counter: ctr("workflow_failed"),
276
- wf_cont_counter: ctr("workflow_continue_as_new"),
277
- wf_e2e_latency: hst(WF_E2E_LATENCY_NAME),
278
- wf_task_queue_poll_empty_counter: ctr("workflow_task_queue_poll_empty"),
279
- wf_task_queue_poll_succeed_counter: ctr("workflow_task_queue_poll_succeed"),
280
- wf_task_execution_failure_counter: ctr("workflow_task_queue_poll_failed"),
281
- wf_task_sched_to_start_latency: hst(WF_TASK_SCHED_TO_START_LATENCY_NAME),
282
- wf_task_replay_latency: hst(WF_TASK_REPLAY_LATENCY_NAME),
283
- wf_task_execution_latency: hst(WF_TASK_EXECUTION_LATENCY_NAME),
284
- act_poll_no_task: ctr("activity_poll_no_task"),
285
- act_task_received_counter: ctr("activity_task_received"),
286
- act_execution_failed: ctr("activity_execution_failed"),
287
- act_sched_to_start_latency: hst(ACT_SCHED_TO_START_LATENCY_NAME),
288
- act_exec_latency: hst(ACT_EXEC_LATENCY_NAME),
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: ctr("worker_start"),
291
- num_pollers: hst(NUM_POLLERS_NAME),
292
- task_slots_available: hst(TASK_SLOTS_AVAILABLE_NAME),
293
- sticky_cache_hit: ctr("sticky_cache_hit"),
294
- sticky_cache_miss: ctr("sticky_cache_miss"),
295
- sticky_cache_size: hst(STICKY_CACHE_SIZE_NAME),
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
  }