@temporalio/core-bridge 1.9.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +754 -473
- package/Cargo.toml +3 -3
- package/lib/index.d.ts +33 -2
- package/lib/index.js.map +1 -1
- package/package.json +4 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/scripts/build.js +4 -3
- package/sdk-core/.cargo/config.toml +2 -4
- package/sdk-core/.github/workflows/heavy.yml +1 -1
- package/sdk-core/.github/workflows/per-pr.yml +6 -4
- package/sdk-core/Cargo.toml +10 -3
- package/sdk-core/README.md +4 -6
- package/sdk-core/client/Cargo.toml +13 -5
- package/sdk-core/client/src/lib.rs +123 -34
- package/sdk-core/client/src/metrics.rs +70 -18
- package/sdk-core/client/src/proxy.rs +85 -0
- package/sdk-core/client/src/raw.rs +67 -5
- package/sdk-core/client/src/worker_registry/mod.rs +5 -3
- package/sdk-core/client/src/workflow_handle/mod.rs +3 -1
- package/sdk-core/core/Cargo.toml +31 -37
- package/sdk-core/core/src/abstractions/take_cell.rs +3 -3
- package/sdk-core/core/src/abstractions.rs +176 -108
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -13
- package/sdk-core/core/src/core_tests/determinism.rs +2 -1
- package/sdk-core/core/src/core_tests/local_activities.rs +3 -3
- package/sdk-core/core/src/core_tests/mod.rs +3 -3
- package/sdk-core/core/src/core_tests/queries.rs +42 -5
- package/sdk-core/core/src/core_tests/workers.rs +2 -3
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +115 -15
- package/sdk-core/core/src/ephemeral_server/mod.rs +109 -136
- package/sdk-core/core/src/internal_flags.rs +8 -8
- package/sdk-core/core/src/lib.rs +16 -11
- package/sdk-core/core/src/pollers/mod.rs +11 -5
- package/sdk-core/core/src/pollers/poll_buffer.rs +48 -29
- package/sdk-core/core/src/protosext/mod.rs +32 -32
- package/sdk-core/core/src/protosext/protocol_messages.rs +14 -24
- package/sdk-core/core/src/retry_logic.rs +2 -2
- package/sdk-core/core/src/telemetry/log_export.rs +10 -9
- package/sdk-core/core/src/telemetry/metrics.rs +233 -330
- package/sdk-core/core/src/telemetry/mod.rs +11 -38
- package/sdk-core/core/src/telemetry/otel.rs +355 -0
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -23
- package/sdk-core/core/src/test_help/mod.rs +80 -59
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +6 -6
- package/sdk-core/core/src/worker/activities/local_activities.rs +46 -43
- package/sdk-core/core/src/worker/activities.rs +45 -46
- package/sdk-core/core/src/worker/client/mocks.rs +8 -7
- package/sdk-core/core/src/worker/client.rs +40 -39
- package/sdk-core/core/src/worker/mod.rs +72 -42
- package/sdk-core/core/src/worker/slot_provider.rs +28 -28
- package/sdk-core/core/src/worker/slot_supplier.rs +1 -0
- package/sdk-core/core/src/worker/tuner/fixed_size.rs +52 -0
- package/sdk-core/core/src/worker/tuner/resource_based.rs +561 -0
- package/sdk-core/core/src/worker/tuner.rs +122 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +6 -6
- package/sdk-core/core/src/worker/workflow/history_update.rs +27 -53
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +4 -17
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -10
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +4 -11
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +17 -35
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +0 -8
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +0 -14
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -10
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -10
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +12 -8
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +0 -10
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -13
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +27 -37
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +3 -14
- package/sdk-core/core/src/worker/workflow/managed_run.rs +84 -54
- package/sdk-core/core/src/worker/workflow/mod.rs +63 -160
- package/sdk-core/core/src/worker/workflow/run_cache.rs +22 -13
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +16 -3
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +15 -12
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +39 -78
- package/sdk-core/core-api/Cargo.toml +6 -5
- package/sdk-core/core-api/src/errors.rs +8 -0
- package/sdk-core/core-api/src/telemetry/metrics.rs +75 -4
- package/sdk-core/core-api/src/telemetry.rs +7 -1
- package/sdk-core/core-api/src/worker.rs +212 -56
- package/sdk-core/fsm/Cargo.toml +3 -0
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
- package/sdk-core/sdk/Cargo.toml +5 -7
- package/sdk-core/sdk/src/app_data.rs +3 -3
- package/sdk-core/sdk/src/lib.rs +5 -3
- package/sdk-core/sdk/src/workflow_context/options.rs +1 -1
- package/sdk-core/sdk/src/workflow_context.rs +10 -9
- package/sdk-core/sdk/src/workflow_future.rs +1 -1
- package/sdk-core/sdk-core-protos/Cargo.toml +8 -6
- package/sdk-core/sdk-core-protos/build.rs +1 -10
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +3 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/ci.yml +26 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +42 -20
- package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +36 -26
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/struct.proto +95 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +9632 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +7337 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/payload_description.txt +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +45 -11
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +22 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +44 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +18 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +30 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +7 -8
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +23 -5
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +25 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +141 -15
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +12 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +193 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +73 -6
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +46 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +4 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +2 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +116 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +134 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +274 -29
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +57 -1
- package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +10 -12
- package/sdk-core/sdk-core-protos/src/history_builder.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +54 -51
- package/sdk-core/sdk-core-protos/src/task_token.rs +11 -2
- package/sdk-core/test-utils/Cargo.toml +7 -4
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +44 -62
- package/sdk-core/tests/fuzzy_workflow.rs +5 -2
- package/sdk-core/tests/heavy_tests.rs +114 -17
- package/sdk-core/tests/integ_tests/activity_functions.rs +1 -1
- package/sdk-core/tests/integ_tests/client_tests.rs +2 -2
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +38 -26
- package/sdk-core/tests/integ_tests/metrics_tests.rs +126 -17
- package/sdk-core/tests/integ_tests/polling_tests.rs +118 -2
- package/sdk-core/tests/integ_tests/update_tests.rs +3 -5
- package/sdk-core/tests/integ_tests/visibility_tests.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -4
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -2
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +6 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +9 -7
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +14 -9
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +6 -13
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +9 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +5 -5
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +115 -11
- package/sdk-core/tests/main.rs +2 -2
- package/src/conversions.rs +57 -0
- package/src/lib.rs +1 -0
- package/src/runtime.rs +51 -35
- package/ts/index.ts +67 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +0 -117
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +0 -24
- package/sdk-core/sdk/src/payload_converter.rs +0 -11
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/docker-compose.yml +0 -15
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/pipeline.yml +0 -10
- package/sdk-core/test-utils/src/wf_input_saver.rs +0 -50
- package/sdk-core/tests/wf_input_replay.rs +0 -32
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
use
|
|
2
|
-
use
|
|
1
|
+
use crate::{errors::WorkflowErrorType, telemetry::metrics::TemporalMeter};
|
|
2
|
+
use std::{
|
|
3
|
+
any::Any,
|
|
4
|
+
collections::{HashMap, HashSet},
|
|
5
|
+
sync::Arc,
|
|
6
|
+
time::Duration,
|
|
7
|
+
};
|
|
3
8
|
|
|
4
|
-
const MAX_OUTSTANDING_WFT_DEFAULT: usize = 100;
|
|
5
9
|
const MAX_CONCURRENT_WFT_POLLS_DEFAULT: usize = 5;
|
|
6
10
|
|
|
7
11
|
/// Defines per-worker configuration options
|
|
8
|
-
#[derive(
|
|
12
|
+
#[derive(Clone, derive_builder::Builder)]
|
|
9
13
|
#[builder(setter(into), build_fn(validate = "Self::validate"))]
|
|
10
14
|
#[non_exhaustive]
|
|
11
15
|
pub struct WorkerConfig {
|
|
@@ -29,20 +33,10 @@ pub struct WorkerConfig {
|
|
|
29
33
|
/// or failures.
|
|
30
34
|
#[builder(default = "0")]
|
|
31
35
|
pub max_cached_workflows: usize,
|
|
32
|
-
///
|
|
33
|
-
///
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/// Cannot be larger than `max_cached_workflows`.
|
|
37
|
-
#[builder(default = "MAX_OUTSTANDING_WFT_DEFAULT")]
|
|
38
|
-
pub max_outstanding_workflow_tasks: usize,
|
|
39
|
-
/// The maximum number of activity tasks that will ever be given to this worker concurrently
|
|
40
|
-
#[builder(default = "100")]
|
|
41
|
-
pub max_outstanding_activities: usize,
|
|
42
|
-
/// The maximum number of local activity tasks that will ever be given to this worker
|
|
43
|
-
/// concurrently
|
|
44
|
-
#[builder(default = "100")]
|
|
45
|
-
pub max_outstanding_local_activities: usize,
|
|
36
|
+
/// Set a [WorkerTuner] for this worker. Either this or at least one of the `max_outstanding_*`
|
|
37
|
+
/// fields must be set.
|
|
38
|
+
#[builder(setter(into = false, strip_option), default)]
|
|
39
|
+
pub tuner: Option<Arc<dyn WorkerTuner + Send + Sync>>,
|
|
46
40
|
/// Maximum number of concurrent poll workflow task requests we will perform at a time on this
|
|
47
41
|
/// worker's task queue. See also [WorkerConfig::nonsticky_to_sticky_poll_ratio]. Must be at
|
|
48
42
|
/// least 1.
|
|
@@ -115,14 +109,6 @@ pub struct WorkerConfig {
|
|
|
115
109
|
#[builder(default = "5")]
|
|
116
110
|
pub fetching_concurrency: usize,
|
|
117
111
|
|
|
118
|
-
// TODO: Move this out - dependency on tokio should not exist just for this
|
|
119
|
-
/// If set, and the `save_wf_inputs` feature is enabled in core, will be sent a serialized
|
|
120
|
-
/// instance of every input to workflow state in order. This is for testing purposes, SDK
|
|
121
|
-
/// implementations never need to care about it.
|
|
122
|
-
#[builder(default)]
|
|
123
|
-
#[serde(skip)]
|
|
124
|
-
pub wf_state_inputs: Option<UnboundedSender<Vec<u8>>>,
|
|
125
|
-
|
|
126
112
|
/// If set, core will issue cancels for all outstanding activities after shutdown has been
|
|
127
113
|
/// initiated and this amount of time has elapsed.
|
|
128
114
|
#[builder(default)]
|
|
@@ -133,6 +119,35 @@ pub struct WorkerConfig {
|
|
|
133
119
|
/// timeout.
|
|
134
120
|
#[builder(default = "Duration::from_secs(5)")]
|
|
135
121
|
pub local_timeout_buffer_for_activities: Duration,
|
|
122
|
+
|
|
123
|
+
/// Any error types listed here will cause any workflow being processed by this worker to fail,
|
|
124
|
+
/// rather than simply failing the workflow task.
|
|
125
|
+
#[builder(default)]
|
|
126
|
+
pub workflow_failure_errors: HashSet<WorkflowErrorType>,
|
|
127
|
+
|
|
128
|
+
/// Like [WorkerConfig::workflow_failure_errors], but specific to certain workflow types (the
|
|
129
|
+
/// map key).
|
|
130
|
+
#[builder(default)]
|
|
131
|
+
pub workflow_types_to_failure_errors: HashMap<String, HashSet<WorkflowErrorType>>,
|
|
132
|
+
|
|
133
|
+
/// The maximum allowed number of workflow tasks that will ever be given to this worker at one
|
|
134
|
+
/// time. Note that one workflow task may require multiple activations - so the WFT counts as
|
|
135
|
+
/// "outstanding" until all activations it requires have been completed.
|
|
136
|
+
///
|
|
137
|
+
/// Mutually exclusive with `tuner`
|
|
138
|
+
#[builder(setter(into, strip_option), default)]
|
|
139
|
+
pub max_outstanding_workflow_tasks: Option<usize>,
|
|
140
|
+
/// The maximum number of activity tasks that will ever be given to this worker concurrently
|
|
141
|
+
///
|
|
142
|
+
/// Mutually exclusive with `tuner`
|
|
143
|
+
#[builder(setter(into, strip_option), default)]
|
|
144
|
+
pub max_outstanding_activities: Option<usize>,
|
|
145
|
+
/// The maximum number of local activity tasks that will ever be given to this worker
|
|
146
|
+
/// concurrently
|
|
147
|
+
///
|
|
148
|
+
/// Mutually exclusive with `tuner`
|
|
149
|
+
#[builder(setter(into, strip_option), default)]
|
|
150
|
+
pub max_outstanding_local_activities: Option<usize>,
|
|
136
151
|
}
|
|
137
152
|
|
|
138
153
|
impl WorkerConfig {
|
|
@@ -145,9 +160,31 @@ impl WorkerConfig {
|
|
|
145
160
|
.saturating_sub(self.max_nonsticky_polls())
|
|
146
161
|
.max(1)
|
|
147
162
|
}
|
|
163
|
+
/// Returns true if the configuration specifies we should fail a workflow on a certain error
|
|
164
|
+
/// type rather than failing the workflow task.
|
|
165
|
+
pub fn should_fail_workflow(
|
|
166
|
+
&self,
|
|
167
|
+
workflow_type: &str,
|
|
168
|
+
error_type: &WorkflowErrorType,
|
|
169
|
+
) -> bool {
|
|
170
|
+
self.workflow_failure_errors.contains(error_type)
|
|
171
|
+
|| self
|
|
172
|
+
.workflow_types_to_failure_errors
|
|
173
|
+
.get(workflow_type)
|
|
174
|
+
.map(|s| s.contains(error_type))
|
|
175
|
+
.unwrap_or(false)
|
|
176
|
+
}
|
|
148
177
|
}
|
|
149
178
|
|
|
150
179
|
impl WorkerConfigBuilder {
|
|
180
|
+
/// Unset all `max_outstanding_*` fields
|
|
181
|
+
pub fn clear_max_outstanding_opts(&mut self) -> &mut Self {
|
|
182
|
+
self.max_outstanding_workflow_tasks = None;
|
|
183
|
+
self.max_outstanding_activities = None;
|
|
184
|
+
self.max_outstanding_local_activities = None;
|
|
185
|
+
self
|
|
186
|
+
}
|
|
187
|
+
|
|
151
188
|
fn validate(&self) -> Result<(), String> {
|
|
152
189
|
if self.max_concurrent_wft_polls == Some(0) {
|
|
153
190
|
return Err("`max_concurrent_wft_polls` must be at least 1".to_owned());
|
|
@@ -155,15 +192,7 @@ impl WorkerConfigBuilder {
|
|
|
155
192
|
if self.max_concurrent_at_polls == Some(0) {
|
|
156
193
|
return Err("`max_concurrent_at_polls` must be at least 1".to_owned());
|
|
157
194
|
}
|
|
158
|
-
|
|
159
|
-
&& self.max_outstanding_workflow_tasks > self.max_cached_workflows
|
|
160
|
-
{
|
|
161
|
-
return Err(
|
|
162
|
-
"Maximum concurrent workflow tasks cannot exceed the maximum number of cached \
|
|
163
|
-
workflows"
|
|
164
|
-
.to_owned(),
|
|
165
|
-
);
|
|
166
|
-
}
|
|
195
|
+
|
|
167
196
|
if let Some(Some(ref x)) = self.max_worker_activities_per_second {
|
|
168
197
|
if !x.is_normal() || x.is_sign_negative() {
|
|
169
198
|
return Err(
|
|
@@ -171,30 +200,28 @@ impl WorkerConfigBuilder {
|
|
|
171
200
|
);
|
|
172
201
|
}
|
|
173
202
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
&& self
|
|
177
|
-
.
|
|
178
|
-
.
|
|
179
|
-
<= 1
|
|
203
|
+
|
|
204
|
+
if self.tuner.is_some()
|
|
205
|
+
&& (self.max_outstanding_workflow_tasks.is_some()
|
|
206
|
+
|| self.max_outstanding_activities.is_some()
|
|
207
|
+
|| self.max_outstanding_local_activities.is_some())
|
|
180
208
|
{
|
|
181
|
-
return Err(
|
|
182
|
-
"`max_outstanding_workflow_tasks` must be at at least 2 when \
|
|
183
|
-
`max_cached_workflows` is nonzero"
|
|
184
|
-
.to_owned(),
|
|
185
|
-
);
|
|
209
|
+
return Err("max_outstanding_* fields are mutually exclusive with `tuner`".to_owned());
|
|
186
210
|
}
|
|
187
|
-
|
|
211
|
+
|
|
212
|
+
let max_wft_polls = self
|
|
188
213
|
.max_concurrent_wft_polls
|
|
189
|
-
.unwrap_or(MAX_CONCURRENT_WFT_POLLS_DEFAULT)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
214
|
+
.unwrap_or(MAX_CONCURRENT_WFT_POLLS_DEFAULT);
|
|
215
|
+
|
|
216
|
+
// It wouldn't make any sense to have more outstanding polls than workflows we can possibly
|
|
217
|
+
// cache. If we allow this at low values it's possible for sticky pollers to reserve all
|
|
218
|
+
// available slots, crowding out the normal queue and gumming things up.
|
|
219
|
+
if let Some(max_cache) = self.max_cached_workflows {
|
|
220
|
+
if max_cache > 0 && max_wft_polls > max_cache {
|
|
221
|
+
return Err(
|
|
222
|
+
"`max_concurrent_wft_polls` cannot exceed `max_cached_workflows`".to_owned(),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
198
225
|
}
|
|
199
226
|
|
|
200
227
|
if self.use_worker_versioning.unwrap_or_default()
|
|
@@ -212,3 +239,132 @@ impl WorkerConfigBuilder {
|
|
|
212
239
|
Ok(())
|
|
213
240
|
}
|
|
214
241
|
}
|
|
242
|
+
|
|
243
|
+
/// This trait allows users to customize the performance characteristics of workers dynamically.
|
|
244
|
+
/// For more, see the docstrings of the traits in the return types of its functions.
|
|
245
|
+
pub trait WorkerTuner {
|
|
246
|
+
/// Return a [SlotSupplier] for workflow tasks
|
|
247
|
+
fn workflow_task_slot_supplier(
|
|
248
|
+
&self,
|
|
249
|
+
) -> Arc<dyn SlotSupplier<SlotKind = WorkflowSlotKind> + Send + Sync>;
|
|
250
|
+
|
|
251
|
+
/// Return a [SlotSupplier] for activity tasks
|
|
252
|
+
fn activity_task_slot_supplier(
|
|
253
|
+
&self,
|
|
254
|
+
) -> Arc<dyn SlotSupplier<SlotKind = ActivitySlotKind> + Send + Sync>;
|
|
255
|
+
|
|
256
|
+
/// Return a [SlotSupplier] for local activities
|
|
257
|
+
fn local_activity_slot_supplier(
|
|
258
|
+
&self,
|
|
259
|
+
) -> Arc<dyn SlotSupplier<SlotKind = LocalActivitySlotKind> + Send + Sync>;
|
|
260
|
+
|
|
261
|
+
/// Core will call this at worker initialization time, allowing the implementation to hook up to
|
|
262
|
+
/// metrics if any are configured. If not, it will not be called.
|
|
263
|
+
fn attach_metrics(&self, metrics: TemporalMeter);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// Implementing this trait allows users to customize how many tasks of certain kinds the worker
|
|
267
|
+
/// will perform concurrently.
|
|
268
|
+
///
|
|
269
|
+
/// Note that, for implementations on workflow tasks ([WorkflowSlotKind]), workers that have the
|
|
270
|
+
/// workflow cache enabled should be willing to hand out _at least_ two slots, to avoid the worker
|
|
271
|
+
/// becoming stuck only polling on the worker's sticky queue.
|
|
272
|
+
#[async_trait::async_trait]
|
|
273
|
+
pub trait SlotSupplier {
|
|
274
|
+
type SlotKind: SlotKind;
|
|
275
|
+
/// Block until a slot is available, then return a permit for the slot.
|
|
276
|
+
async fn reserve_slot(&self, ctx: &dyn SlotReservationContext) -> SlotSupplierPermit;
|
|
277
|
+
|
|
278
|
+
/// Try to immediately reserve a slot, returning None if one is not available
|
|
279
|
+
fn try_reserve_slot(&self, ctx: &dyn SlotReservationContext) -> Option<SlotSupplierPermit>;
|
|
280
|
+
|
|
281
|
+
/// Marks a slot as actually now being used. This is separate from reserving one because the
|
|
282
|
+
/// pollers need to reserve a slot before they have actually obtained work from server. Once
|
|
283
|
+
/// that task is obtained (and validated) then the slot can actually be used to work on the
|
|
284
|
+
/// task.
|
|
285
|
+
///
|
|
286
|
+
/// Users' implementation of this can choose to emit metrics, or otherwise leverage the
|
|
287
|
+
/// information provided by the `info` parameter to be better able to make future decisions
|
|
288
|
+
/// about whether a slot should be handed out.
|
|
289
|
+
fn mark_slot_used(&self, info: <Self::SlotKind as SlotKind>::Info<'_>);
|
|
290
|
+
|
|
291
|
+
/// Frees a slot.
|
|
292
|
+
fn release_slot(&self);
|
|
293
|
+
|
|
294
|
+
/// If this implementation knows how many slots are available at any moment, it should return
|
|
295
|
+
/// that here.
|
|
296
|
+
fn available_slots(&self) -> Option<usize> {
|
|
297
|
+
None
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
pub trait SlotReservationContext: Send + Sync {
|
|
302
|
+
/// Returns the number of currently outstanding slot permits, whether used or un-used.
|
|
303
|
+
fn num_issued_slots(&self) -> usize;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
#[derive(Default)]
|
|
307
|
+
pub struct SlotSupplierPermit {
|
|
308
|
+
user_data: Option<Box<dyn Any + Send + Sync>>,
|
|
309
|
+
}
|
|
310
|
+
impl SlotSupplierPermit {
|
|
311
|
+
pub fn with_user_data<T: Any + Send + Sync>(user_data: T) -> Self {
|
|
312
|
+
Self {
|
|
313
|
+
user_data: Some(Box::new(user_data)),
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/// Attempts to downcast the inner data, if any, into the provided type and returns it.
|
|
317
|
+
/// Returns none if there is no data or the data is not of the appropriate type.
|
|
318
|
+
pub fn user_data<T: Any + Send + Sync>(&self) -> Option<&T> {
|
|
319
|
+
self.user_data.as_ref().and_then(|b| b.downcast_ref())
|
|
320
|
+
}
|
|
321
|
+
/// Attempts to downcast the inner data, if any, into the provided type and returns it mutably.
|
|
322
|
+
/// Returns none if there is no data or the data is not of the appropriate type.
|
|
323
|
+
pub fn user_data_mut<T: Any + Send + Sync>(&mut self) -> Option<&mut T> {
|
|
324
|
+
self.user_data.as_mut().and_then(|b| b.downcast_mut())
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
pub struct WorkflowSlotInfo<'a> {
|
|
329
|
+
pub workflow_type: &'a str,
|
|
330
|
+
// etc...
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
pub struct ActivitySlotInfo<'a> {
|
|
334
|
+
pub activity_type: &'a str,
|
|
335
|
+
// etc...
|
|
336
|
+
}
|
|
337
|
+
pub struct LocalActivitySlotInfo<'a> {
|
|
338
|
+
pub activity_type: &'a str,
|
|
339
|
+
// etc...
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
#[derive(Debug)]
|
|
343
|
+
pub struct WorkflowSlotKind {}
|
|
344
|
+
#[derive(Debug)]
|
|
345
|
+
pub struct ActivitySlotKind {}
|
|
346
|
+
#[derive(Debug)]
|
|
347
|
+
pub struct LocalActivitySlotKind {}
|
|
348
|
+
pub trait SlotKind {
|
|
349
|
+
type Info<'a>;
|
|
350
|
+
fn kind_name() -> &'static str;
|
|
351
|
+
}
|
|
352
|
+
impl SlotKind for WorkflowSlotKind {
|
|
353
|
+
type Info<'a> = WorkflowSlotInfo<'a>;
|
|
354
|
+
|
|
355
|
+
fn kind_name() -> &'static str {
|
|
356
|
+
"workflow"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
impl SlotKind for ActivitySlotKind {
|
|
360
|
+
type Info<'a> = ActivitySlotInfo<'a>;
|
|
361
|
+
fn kind_name() -> &'static str {
|
|
362
|
+
"activity"
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
impl SlotKind for LocalActivitySlotKind {
|
|
366
|
+
type Info<'a> = LocalActivitySlotInfo<'a>;
|
|
367
|
+
fn kind_name() -> &'static str {
|
|
368
|
+
"local_activity"
|
|
369
|
+
}
|
|
370
|
+
}
|
package/sdk-core/fsm/Cargo.toml
CHANGED
package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr
CHANGED
|
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `One: From<Two>` is not satisfied
|
|
|
2
2
|
--> tests/trybuild/no_handle_conversions_require_into_fail.rs:11:5
|
|
3
3
|
|
|
|
4
4
|
11 | Two --(B)--> One;
|
|
5
|
-
| ^^^ the trait `From<Two>` is not implemented for `One`
|
|
5
|
+
| ^^^ the trait `From<Two>` is not implemented for `One`, which is required by `Two: Into<One>`
|
|
6
6
|
|
|
|
7
7
|
= note: required for `Two` to implement `Into<One>`
|
|
8
8
|
note: required by a bound in `TransitionResult::<Sm, Ds>::from`
|
package/sdk-core/sdk/Cargo.toml
CHANGED
|
@@ -10,30 +10,25 @@ repository = "https://github.com/temporalio/sdk-core"
|
|
|
10
10
|
keywords = ["temporal", "workflow"]
|
|
11
11
|
categories = ["development-tools"]
|
|
12
12
|
|
|
13
|
-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
14
|
-
|
|
15
13
|
[dependencies]
|
|
16
14
|
async-trait = "0.1"
|
|
17
15
|
thiserror = "1.0"
|
|
18
16
|
anyhow = "1.0"
|
|
19
|
-
base64 = "0.21"
|
|
20
17
|
crossbeam-channel = "0.5"
|
|
21
18
|
derive_more = { workspace = true }
|
|
22
19
|
futures = "0.3"
|
|
23
|
-
once_cell = "1.10"
|
|
24
20
|
parking_lot = { version = "0.12", features = ["send_guard"] }
|
|
25
|
-
prost-types = { version = "0.
|
|
26
|
-
sha2 = "0.10"
|
|
21
|
+
prost-types = { version = "0.5", package = "prost-wkt-types" }
|
|
27
22
|
serde = "1.0"
|
|
28
23
|
tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
|
|
29
24
|
tokio-util = { version = "0.7" }
|
|
30
25
|
tokio-stream = "0.1"
|
|
31
|
-
tonic = { workspace = true }
|
|
32
26
|
tracing = "0.1"
|
|
33
27
|
|
|
34
28
|
[dependencies.temporal-sdk-core]
|
|
35
29
|
path = "../core"
|
|
36
30
|
version = "0.1"
|
|
31
|
+
default-features = false
|
|
37
32
|
|
|
38
33
|
[dependencies.temporal-sdk-core-protos]
|
|
39
34
|
path = "../sdk-core-protos"
|
|
@@ -46,3 +41,6 @@ version = "0.1"
|
|
|
46
41
|
[dependencies.temporal-client]
|
|
47
42
|
path = "../client"
|
|
48
43
|
version = "0.1"
|
|
44
|
+
|
|
45
|
+
[lints]
|
|
46
|
+
workspace = true
|
|
@@ -6,20 +6,20 @@ use std::{
|
|
|
6
6
|
|
|
7
7
|
/// A Wrapper Type for workflow and activity app data
|
|
8
8
|
#[derive(Default)]
|
|
9
|
-
pub struct AppData {
|
|
9
|
+
pub(crate) struct AppData {
|
|
10
10
|
map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
impl AppData {
|
|
14
14
|
/// Insert an item, overwritting duplicates
|
|
15
|
-
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
|
|
15
|
+
pub(crate) fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
|
|
16
16
|
self.map
|
|
17
17
|
.insert(TypeId::of::<T>(), Box::new(val))
|
|
18
18
|
.and_then(downcast_owned)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/// Get a reference to a type in the map
|
|
22
|
-
pub fn get<T: 'static>(&self) -> Option<&T> {
|
|
22
|
+
pub(crate) fn get<T: 'static>(&self) -> Option<&T> {
|
|
23
23
|
self.map
|
|
24
24
|
.get(&TypeId::of::<T>())
|
|
25
25
|
.and_then(|boxed| boxed.downcast_ref())
|
package/sdk-core/sdk/src/lib.rs
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
18
18
|
//! let server_options = sdk_client_options(Url::from_str("http://localhost:7233")?).build()?;
|
|
19
19
|
//!
|
|
20
|
-
//! let client = server_options.connect("default", None
|
|
20
|
+
//! let client = server_options.connect("default", None).await?;
|
|
21
21
|
//!
|
|
22
22
|
//! let telemetry_options = TelemetryOptionsBuilder::default().build()?;
|
|
23
23
|
//! let runtime = CoreRuntime::new_assume_tokio(telemetry_options)?;
|
|
@@ -48,7 +48,6 @@ extern crate tracing;
|
|
|
48
48
|
mod activity_context;
|
|
49
49
|
mod app_data;
|
|
50
50
|
pub mod interceptors;
|
|
51
|
-
mod payload_converter;
|
|
52
51
|
mod workflow_context;
|
|
53
52
|
mod workflow_future;
|
|
54
53
|
|
|
@@ -521,7 +520,10 @@ impl ActivityHalf {
|
|
|
521
520
|
});
|
|
522
521
|
}
|
|
523
522
|
Some(activity_task::Variant::Cancel(_)) => {
|
|
524
|
-
if let Some(ct) = self
|
|
523
|
+
if let Some(ct) = self
|
|
524
|
+
.task_tokens_to_cancels
|
|
525
|
+
.get(activity.task_token.as_slice())
|
|
526
|
+
{
|
|
525
527
|
ct.cancel();
|
|
526
528
|
}
|
|
527
529
|
}
|
|
@@ -17,7 +17,7 @@ use temporal_sdk_core_protos::{
|
|
|
17
17
|
|
|
18
18
|
// TODO: Before release, probably best to avoid using proto types entirely here. They're awkward.
|
|
19
19
|
|
|
20
|
-
pub trait IntoWorkflowCommand {
|
|
20
|
+
pub(crate) trait IntoWorkflowCommand {
|
|
21
21
|
type WFCommandType;
|
|
22
22
|
|
|
23
23
|
/// Produces a workflow command from some options
|
|
@@ -98,11 +98,11 @@ impl WfCtxProtectedDat {
|
|
|
98
98
|
#[derive(Clone, Debug, Default)]
|
|
99
99
|
pub(crate) struct WfContextSharedData {
|
|
100
100
|
/// Maps change ids -> resolved status
|
|
101
|
-
pub changes: HashMap<String, bool>,
|
|
102
|
-
pub is_replaying: bool,
|
|
103
|
-
pub wf_time: Option<SystemTime>,
|
|
104
|
-
pub history_length: u32,
|
|
105
|
-
pub current_build_id: Option<String>,
|
|
101
|
+
pub(crate) changes: HashMap<String, bool>,
|
|
102
|
+
pub(crate) is_replaying: bool,
|
|
103
|
+
pub(crate) wf_time: Option<SystemTime>,
|
|
104
|
+
pub(crate) history_length: u32,
|
|
105
|
+
pub(crate) current_build_id: Option<String>,
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// TODO: Dataconverter type interface to replace Payloads here. Possibly just use serde
|
|
@@ -204,7 +204,7 @@ impl WfContext {
|
|
|
204
204
|
mut opts: ActivityOptions,
|
|
205
205
|
) -> impl CancellableFuture<ActivityResolution> {
|
|
206
206
|
if opts.task_queue.is_empty() {
|
|
207
|
-
opts.task_queue
|
|
207
|
+
opts.task_queue.clone_from(&self.task_queue);
|
|
208
208
|
}
|
|
209
209
|
let seq = self.seq_nums.write().next_activity_seq();
|
|
210
210
|
let (cmd, unblocker) = CancellableWFCommandFut::new(CancellableID::Activity(seq));
|
|
@@ -573,7 +573,8 @@ impl<'a> Future for LATimerBackoffFut<'a> {
|
|
|
573
573
|
if let TimerResult::Fired = tr {
|
|
574
574
|
let mut opts = self.la_opts.clone();
|
|
575
575
|
opts.attempt = Some(self.next_attempt);
|
|
576
|
-
opts.original_schedule_time
|
|
576
|
+
opts.original_schedule_time
|
|
577
|
+
.clone_from(&self.next_sched_time);
|
|
577
578
|
self.current_fut = Box::pin(self.ctx.local_activity_no_timer_retry(opts));
|
|
578
579
|
Poll::Pending
|
|
579
580
|
} else {
|
|
@@ -608,7 +609,7 @@ impl<'a> Future for LATimerBackoffFut<'a> {
|
|
|
608
609
|
);
|
|
609
610
|
self.timer_fut = Some(Box::pin(timer_f));
|
|
610
611
|
self.next_attempt = b.attempt;
|
|
611
|
-
self.next_sched_time
|
|
612
|
+
self.next_sched_time.clone_from(&b.original_schedule_time);
|
|
612
613
|
return Poll::Pending;
|
|
613
614
|
}
|
|
614
615
|
}
|
|
@@ -631,7 +632,7 @@ pub struct ChildWorkflow {
|
|
|
631
632
|
opts: ChildWorkflowOptions,
|
|
632
633
|
}
|
|
633
634
|
|
|
634
|
-
pub struct ChildWfCommon {
|
|
635
|
+
pub(crate) struct ChildWfCommon {
|
|
635
636
|
workflow_id: String,
|
|
636
637
|
result_future: CancellableWFCommandFut<ChildWorkflowResult, ()>,
|
|
637
638
|
}
|
|
@@ -93,7 +93,7 @@ enum SigChanOrBuffer {
|
|
|
93
93
|
Buffer(Vec<SignalData>),
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
pub struct WorkflowFuture {
|
|
96
|
+
pub(crate) struct WorkflowFuture {
|
|
97
97
|
/// Future produced by calling the workflow function
|
|
98
98
|
inner: BoxFuture<'static, WorkflowResult<Payload>>,
|
|
99
99
|
/// Commands produced inside user's wf code
|
|
@@ -12,15 +12,14 @@ categories = ["development-tools"]
|
|
|
12
12
|
|
|
13
13
|
[features]
|
|
14
14
|
history_builders = ["uuid", "rand"]
|
|
15
|
-
serde_serialize = []
|
|
16
15
|
|
|
17
16
|
[dependencies]
|
|
18
17
|
anyhow = "1.0"
|
|
19
|
-
base64 = "0.
|
|
18
|
+
base64 = "0.22"
|
|
20
19
|
derive_more = { workspace = true }
|
|
21
|
-
prost =
|
|
22
|
-
prost-wkt = "0.
|
|
23
|
-
prost-wkt-types = "0.
|
|
20
|
+
prost = { workspace = true }
|
|
21
|
+
prost-wkt = "0.5"
|
|
22
|
+
prost-wkt-types = "0.5"
|
|
24
23
|
rand = { version = "0.8", optional = true }
|
|
25
24
|
serde = { version = "1.0", features = ["derive"] }
|
|
26
25
|
serde_json = "1.0"
|
|
@@ -30,4 +29,7 @@ uuid = { version = "1.1", features = ["v4"], optional = true }
|
|
|
30
29
|
|
|
31
30
|
[build-dependencies]
|
|
32
31
|
tonic-build = { workspace = true }
|
|
33
|
-
prost-wkt-build = "0.
|
|
32
|
+
prost-wkt-build = "0.5"
|
|
33
|
+
|
|
34
|
+
[lints]
|
|
35
|
+
workspace = true
|
|
@@ -112,7 +112,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
112
112
|
".google.protobuf.Value",
|
|
113
113
|
"::prost_wkt_types::Value"
|
|
114
114
|
)
|
|
115
|
-
.file_descriptor_set_path(
|
|
115
|
+
.file_descriptor_set_path(descriptor_file)
|
|
116
116
|
.compile(
|
|
117
117
|
&[
|
|
118
118
|
"./protos/local/temporal/sdk/core/core_interface.proto",
|
|
@@ -129,14 +129,5 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
129
129
|
],
|
|
130
130
|
)?;
|
|
131
131
|
|
|
132
|
-
#[cfg(feature = "serde_serialize")]
|
|
133
|
-
{
|
|
134
|
-
use prost_wkt_build::{FileDescriptorSet, Message};
|
|
135
|
-
|
|
136
|
-
let descriptor_bytes = std::fs::read(descriptor_file)?;
|
|
137
|
-
let descriptor = FileDescriptorSet::decode(&descriptor_bytes[..])?;
|
|
138
|
-
prost_wkt_build::add_serde(out, descriptor);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
132
|
Ok(())
|
|
142
133
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
permissions:
|
|
5
|
+
contents: read
|
|
6
|
+
jobs:
|
|
7
|
+
ci:
|
|
8
|
+
name: ci
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-go@v4
|
|
13
|
+
with:
|
|
14
|
+
go-version: '^1.21'
|
|
15
|
+
- uses: arduino/setup-protoc@v2
|
|
16
|
+
- name: 'Setup jq'
|
|
17
|
+
uses: dcarbone/install-jq-action@v2
|
|
18
|
+
- run: make ci-build
|
|
19
|
+
- name: Fail if the repo is dirty
|
|
20
|
+
run: |
|
|
21
|
+
if [[ -n $(git status --porcelain) ]]; then
|
|
22
|
+
echo "Detected uncommitted changes."
|
|
23
|
+
git status
|
|
24
|
+
git diff
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|