@temporalio/core-bridge 1.9.0-rc.0 → 1.9.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 +511 -472
- package/Cargo.toml +1 -1
- package/lib/errors.js +6 -6
- package/lib/errors.js.map +1 -1
- package/package.json +5 -5
- 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/Cargo.toml +4 -0
- package/sdk-core/LICENSE.txt +0 -2
- package/sdk-core/client/Cargo.toml +1 -1
- package/sdk-core/client/src/lib.rs +2 -4
- package/sdk-core/core/Cargo.toml +1 -1
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
- package/sdk-core/core/src/core_tests/queries.rs +42 -1
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/replay/mod.rs +1 -2
- package/sdk-core/core/src/telemetry/mod.rs +19 -19
- package/sdk-core/core/src/test_help/mod.rs +1 -1
- package/sdk-core/core/src/worker/mod.rs +5 -19
- package/sdk-core/core/src/worker/workflow/history_update.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +35 -1
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +23 -15
- package/sdk-core/core/src/worker/workflow/mod.rs +8 -12
- package/sdk-core/core/src/worker/workflow/run_cache.rs +9 -15
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +4 -6
- package/sdk-core/core-api/Cargo.toml +1 -1
- package/sdk-core/fsm/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -2
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/workflow_future.rs +2 -2
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +3 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +6 -2
- package/sdk-core/sdk-core-protos/src/history_info.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +1 -1
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests.rs +141 -3
- package/src/conversions.rs +47 -22
- package/src/runtime.rs +13 -10
- package/ts/index.ts +2 -2
- package/sdk-core/client/LICENSE.txt +0 -23
- package/sdk-core/core/LICENSE.txt +0 -23
- package/sdk-core/core-api/LICENSE.txt +0 -23
- package/sdk-core/sdk/LICENSE.txt +0 -23
- package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
|
@@ -7,13 +7,12 @@ use crate::{
|
|
|
7
7
|
MetricsContext,
|
|
8
8
|
};
|
|
9
9
|
use lru::LruCache;
|
|
10
|
-
use std::{num::NonZeroUsize, rc::Rc};
|
|
10
|
+
use std::{num::NonZeroUsize, rc::Rc, sync::Arc};
|
|
11
|
+
use temporal_sdk_core_api::worker::WorkerConfig;
|
|
11
12
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::get_system_info_response;
|
|
12
13
|
|
|
13
14
|
pub(super) struct RunCache {
|
|
14
|
-
|
|
15
|
-
namespace: String,
|
|
16
|
-
task_queue: String,
|
|
15
|
+
worker_config: Arc<WorkerConfig>,
|
|
17
16
|
server_capabilities: get_system_info_response::Capabilities,
|
|
18
17
|
/// Run id -> Data
|
|
19
18
|
runs: LruCache<String, ManagedRun>,
|
|
@@ -24,24 +23,20 @@ pub(super) struct RunCache {
|
|
|
24
23
|
|
|
25
24
|
impl RunCache {
|
|
26
25
|
pub fn new(
|
|
27
|
-
|
|
28
|
-
namespace: String,
|
|
29
|
-
task_queue: String,
|
|
26
|
+
worker_config: Arc<WorkerConfig>,
|
|
30
27
|
server_capabilities: get_system_info_response::Capabilities,
|
|
31
28
|
local_activity_request_sink: impl LocalActivityRequestSink,
|
|
32
29
|
metrics: MetricsContext,
|
|
33
30
|
) -> Self {
|
|
34
31
|
// The cache needs room for at least one run, otherwise we couldn't do anything. In
|
|
35
32
|
// "0" size mode, the run is evicted once the workflow task is complete.
|
|
36
|
-
let lru_size = if
|
|
37
|
-
|
|
33
|
+
let lru_size = if worker_config.max_cached_workflows > 0 {
|
|
34
|
+
worker_config.max_cached_workflows
|
|
38
35
|
} else {
|
|
39
36
|
1
|
|
40
37
|
};
|
|
41
38
|
Self {
|
|
42
|
-
|
|
43
|
-
namespace,
|
|
44
|
-
task_queue,
|
|
39
|
+
worker_config,
|
|
45
40
|
server_capabilities,
|
|
46
41
|
runs: LruCache::new(
|
|
47
42
|
NonZeroUsize::new(lru_size).expect("LRU size is guaranteed positive"),
|
|
@@ -68,11 +63,10 @@ impl RunCache {
|
|
|
68
63
|
.with_new_attrs([workflow_type(pwft.work.workflow_type.clone())]);
|
|
69
64
|
let (mrh, rur) = ManagedRun::new(
|
|
70
65
|
RunBasics {
|
|
71
|
-
|
|
66
|
+
worker_config: self.worker_config.clone(),
|
|
72
67
|
workflow_id: pwft.work.execution.workflow_id.clone(),
|
|
73
68
|
workflow_type: pwft.work.workflow_type.clone(),
|
|
74
69
|
run_id: run_id.clone(),
|
|
75
|
-
task_queue: self.task_queue.clone(),
|
|
76
70
|
history: HistoryUpdate::dummy(),
|
|
77
71
|
metrics,
|
|
78
72
|
capabilities: &self.server_capabilities,
|
|
@@ -124,6 +118,6 @@ impl RunCache {
|
|
|
124
118
|
self.runs.len()
|
|
125
119
|
}
|
|
126
120
|
pub fn cache_capacity(&self) -> usize {
|
|
127
|
-
self.
|
|
121
|
+
self.worker_config.max_cached_workflows
|
|
128
122
|
}
|
|
129
123
|
}
|
|
@@ -23,7 +23,7 @@ use tokio_util::sync::CancellationToken;
|
|
|
23
23
|
///
|
|
24
24
|
/// Use `CoreWfStarter::enable_wf_state_input_recording` from the integration test utilities to
|
|
25
25
|
/// activate saving the data to disk, and use the `wf_input_replay` example binary to replay.
|
|
26
|
-
pub async fn replay_wf_state_inputs(
|
|
26
|
+
pub async fn replay_wf_state_inputs(config: WorkerConfig, inputs: impl Stream<Item = Vec<u8>>) {
|
|
27
27
|
use crate::worker::build_wf_basics;
|
|
28
28
|
|
|
29
29
|
let la_resp_q = Arc::new(SegQueue::new());
|
|
@@ -43,7 +43,7 @@ pub async fn replay_wf_state_inputs(mut config: WorkerConfig, inputs: impl Strea
|
|
|
43
43
|
})
|
|
44
44
|
});
|
|
45
45
|
let basics = build_wf_basics(
|
|
46
|
-
|
|
46
|
+
config,
|
|
47
47
|
MetricsContext::no_op(),
|
|
48
48
|
CancellationToken::new(),
|
|
49
49
|
DEFAULT_TEST_CAPABILITIES.clone(),
|
|
@@ -95,21 +95,19 @@ impl WFStream {
|
|
|
95
95
|
let mut state = WFStream {
|
|
96
96
|
buffered_polls_need_cache_slot: Default::default(),
|
|
97
97
|
runs: RunCache::new(
|
|
98
|
-
basics.
|
|
99
|
-
basics.namespace.clone(),
|
|
100
|
-
basics.task_queue.clone(),
|
|
98
|
+
basics.worker_config.clone(),
|
|
101
99
|
basics.server_capabilities.clone(),
|
|
102
100
|
local_activity_request_sink,
|
|
103
101
|
basics.metrics.clone(),
|
|
104
102
|
),
|
|
105
103
|
shutdown_token: basics.shutdown_token,
|
|
106
|
-
ignore_evicts_on_shutdown: basics.ignore_evicts_on_shutdown,
|
|
104
|
+
ignore_evicts_on_shutdown: basics.worker_config.ignore_evicts_on_shutdown,
|
|
107
105
|
metrics: basics.metrics,
|
|
108
106
|
runs_needing_fetching: Default::default(),
|
|
109
107
|
history_fetch_refcounter: Arc::new(HistfetchRC {}),
|
|
110
108
|
|
|
111
109
|
#[cfg(feature = "save_wf_inputs")]
|
|
112
|
-
wf_state_inputs: basics.wf_state_inputs,
|
|
110
|
+
wf_state_inputs: basics.worker_config.wf_state_inputs.clone(),
|
|
113
111
|
};
|
|
114
112
|
all_inputs
|
|
115
113
|
.map(move |action: WFStreamInput| {
|
|
@@ -386,7 +384,7 @@ impl WFStream {
|
|
|
386
384
|
// We accept that there might be query tasks remaining in the buffer if we evicted
|
|
387
385
|
// and re-instantiated here. It's likely those tasks are now invalidated anyway.
|
|
388
386
|
if maybe_buffered.has_tasks() && should_evict {
|
|
389
|
-
|
|
387
|
+
warn!("There were leftover buffered tasks when evicting run");
|
|
390
388
|
}
|
|
391
389
|
}
|
|
392
390
|
}
|
|
@@ -3,7 +3,7 @@ name = "temporal-sdk-core-api"
|
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Spencer Judge <spencer@temporal.io>"]
|
|
6
|
-
license-file =
|
|
6
|
+
license-file = { workspace = true }
|
|
7
7
|
description = "Interface definitions for the Temporal Core SDK"
|
|
8
8
|
homepage = "https://temporal.io/"
|
|
9
9
|
repository = "https://github.com/temporalio/sdk-core"
|
package/sdk-core/fsm/LICENSE.txt
CHANGED
package/sdk-core/sdk/Cargo.toml
CHANGED
|
@@ -3,7 +3,7 @@ name = "temporal-sdk"
|
|
|
3
3
|
version = "0.1.0-alpha.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Spencer Judge <spencer@temporal.io>"]
|
|
6
|
-
license-file =
|
|
6
|
+
license-file = { workspace = true }
|
|
7
7
|
description = "Temporal Rust SDK"
|
|
8
8
|
homepage = "https://temporal.io/"
|
|
9
9
|
repository = "https://github.com/temporalio/sdk-core"
|
|
@@ -236,7 +236,7 @@ impl WorkflowFuture {
|
|
|
236
236
|
let defp = Payload::default();
|
|
237
237
|
let val_res = if u.run_validator {
|
|
238
238
|
match panic::catch_unwind(AssertUnwindSafe(|| {
|
|
239
|
-
(impls.validator)(&info, u.input.
|
|
239
|
+
(impls.validator)(&info, u.input.first().unwrap_or(&defp))
|
|
240
240
|
})) {
|
|
241
241
|
Ok(r) => r,
|
|
242
242
|
Err(e) => {
|
|
@@ -257,7 +257,7 @@ impl WorkflowFuture {
|
|
|
257
257
|
wf_ctx: self.wf_ctx.clone(),
|
|
258
258
|
info,
|
|
259
259
|
},
|
|
260
|
-
u.input.
|
|
260
|
+
u.input.first().unwrap_or(&defp),
|
|
261
261
|
);
|
|
262
262
|
self.update_futures
|
|
263
263
|
.push((u.protocol_instance_id, handler_fut));
|
|
@@ -3,7 +3,7 @@ name = "temporal-sdk-core-protos"
|
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Spencer Judge <spencer@temporal.io>"]
|
|
6
|
-
license-file =
|
|
6
|
+
license-file = { workspace = true }
|
|
7
7
|
description = "Protobuf definitions for Temporal SDKs Core/Lang interface"
|
|
8
8
|
homepage = "https://temporal.io/"
|
|
9
9
|
repository = "https://github.com/temporalio/sdk-core"
|
|
@@ -90,10 +90,15 @@ message BatchOperationDeletion {
|
|
|
90
90
|
// BatchOperationReset sends reset requests to batch workflows.
|
|
91
91
|
// Keep the parameter in sync with temporal.api.workflowservice.v1.ResetWorkflowExecutionRequest.
|
|
92
92
|
message BatchOperationReset {
|
|
93
|
-
// Reset type.
|
|
94
|
-
temporal.api.enums.v1.ResetType reset_type = 1;
|
|
95
|
-
// History event reapply options.
|
|
96
|
-
temporal.api.enums.v1.ResetReapplyType reset_reapply_type = 2;
|
|
97
93
|
// The identity of the worker/client.
|
|
98
94
|
string identity = 3;
|
|
95
|
+
|
|
96
|
+
// Describes what to reset to and how. If set, `reset_type` and `reset_reapply_type` are ignored.
|
|
97
|
+
temporal.api.common.v1.ResetOptions options = 4;
|
|
98
|
+
|
|
99
|
+
// Reset type (deprecated, use `options`).
|
|
100
|
+
temporal.api.enums.v1.ResetType reset_type = 1;
|
|
101
|
+
// History event reapply options (deprecated, use `options`).
|
|
102
|
+
temporal.api.enums.v1.ResetReapplyType reset_reapply_type = 2;
|
|
103
|
+
|
|
99
104
|
}
|
|
@@ -32,8 +32,10 @@ option ruby_package = "Temporalio::Api::Common::V1";
|
|
|
32
32
|
option csharp_namespace = "Temporalio.Api.Common.V1";
|
|
33
33
|
|
|
34
34
|
import "google/protobuf/duration.proto";
|
|
35
|
+
import "google/protobuf/empty.proto";
|
|
35
36
|
|
|
36
37
|
import "temporal/api/enums/v1/common.proto";
|
|
38
|
+
import "temporal/api/enums/v1/reset.proto";
|
|
37
39
|
|
|
38
40
|
message DataBlob {
|
|
39
41
|
temporal.api.enums.v1.EncodingType encoding_type = 1;
|
|
@@ -147,3 +149,32 @@ message WorkerVersionCapabilities {
|
|
|
147
149
|
|
|
148
150
|
// Later, may include info like "I can process WASM and/or JS bundles"
|
|
149
151
|
}
|
|
152
|
+
|
|
153
|
+
// Describes where and how to reset a workflow, used for batch reset currently
|
|
154
|
+
// and may be used for single-workflow reset later.
|
|
155
|
+
message ResetOptions {
|
|
156
|
+
// Which workflow task to reset to.
|
|
157
|
+
oneof target {
|
|
158
|
+
// Resets to the first workflow task completed or started event.
|
|
159
|
+
google.protobuf.Empty first_workflow_task = 1;
|
|
160
|
+
// Resets to the last workflow task completed or started event.
|
|
161
|
+
google.protobuf.Empty last_workflow_task = 2;
|
|
162
|
+
// The id of a specific `WORKFLOW_TASK_COMPLETED`,`WORKFLOW_TASK_TIMED_OUT`, `WORKFLOW_TASK_FAILED`, or
|
|
163
|
+
// `WORKFLOW_TASK_STARTED` event to reset to.
|
|
164
|
+
// Note that this option doesn't make sense when used as part of a batch request.
|
|
165
|
+
int64 workflow_task_id = 3;
|
|
166
|
+
// Resets to the first workflow task processed by this build id.
|
|
167
|
+
// If the workflow was not processed by the build id, or the workflow task can't be
|
|
168
|
+
// determined, no reset will be performed.
|
|
169
|
+
// Note that by default, this reset is allowed to be to a prior run in a chain of
|
|
170
|
+
// continue-as-new.
|
|
171
|
+
string build_id = 4;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// History event reapply options.
|
|
175
|
+
temporal.api.enums.v1.ResetReapplyType reset_reapply_type = 10;
|
|
176
|
+
|
|
177
|
+
// If true, limit the reset to only within the current run. (Applies to build_id targets and
|
|
178
|
+
// possibly others in the future.)
|
|
179
|
+
bool current_run_only = 11;
|
|
180
|
+
}
|
|
@@ -40,11 +40,11 @@ enum ResetReapplyType {
|
|
|
40
40
|
RESET_REAPPLY_TYPE_NONE = 2;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// Reset type options
|
|
44
|
-
enum ResetType {
|
|
43
|
+
// Reset type options. Deprecated, see temporal.api.common.v1.ResetOptions.
|
|
44
|
+
enum ResetType {
|
|
45
45
|
RESET_TYPE_UNSPECIFIED = 0;
|
|
46
46
|
// Resets to event of the first workflow task completed, or if it does not exist, the event after task scheduled.
|
|
47
47
|
RESET_TYPE_FIRST_WORKFLOW_TASK = 1;
|
|
48
48
|
// Resets to event of the last workflow task completed, or if it does not exist, the event after task scheduled.
|
|
49
49
|
RESET_TYPE_LAST_WORKFLOW_TASK = 2;
|
|
50
|
-
}
|
|
50
|
+
}
|
|
@@ -24,7 +24,7 @@ syntax = "proto3";
|
|
|
24
24
|
|
|
25
25
|
package temporal.api.export.v1;
|
|
26
26
|
|
|
27
|
-
option go_package = "go.temporal.io/api/export/v1;
|
|
27
|
+
option go_package = "go.temporal.io/api/export/v1;export";
|
|
28
28
|
option java_package = "io.temporal.api.export.v1";
|
|
29
29
|
option java_multiple_files = true;
|
|
30
30
|
option java_outer_classname = "MessageProto";
|
package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// The MIT License
|
|
2
|
+
//
|
|
3
|
+
// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
// in the Software without restriction, including without limitation the rights
|
|
8
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
// furnished to do so, subject to the following conditions:
|
|
11
|
+
//
|
|
12
|
+
// The above copyright notice and this permission notice shall be included in
|
|
13
|
+
// all copies or substantial portions of the Software.
|
|
14
|
+
//
|
|
15
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
// THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
syntax = "proto3";
|
|
24
|
+
|
|
25
|
+
package temporal.api.sdk.v1;
|
|
26
|
+
|
|
27
|
+
option go_package = "go.temporal.io/api/sdk/v1;sdk";
|
|
28
|
+
option java_package = "io.temporal.api.sdk.v1";
|
|
29
|
+
option java_multiple_files = true;
|
|
30
|
+
option java_outer_classname = "WorkflowMetadataProto";
|
|
31
|
+
option ruby_package = "Temporalio::Api::Sdk::V1";
|
|
32
|
+
option csharp_namespace = "Temporalio.Api.Sdk.V1";
|
|
33
|
+
|
|
34
|
+
// The name of the query to retrieve this information is `__temporal_getWorkflowMetadata`.
|
|
35
|
+
message WorkflowMetadata {
|
|
36
|
+
// Metadata provided at declaration or creation time.
|
|
37
|
+
WorkflowDefinition definition = 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// (-- api-linter: core::0203::optional=disabled --)
|
|
41
|
+
message WorkflowDefinition {
|
|
42
|
+
// A name scoped by the task queue that maps to this workflow definition.
|
|
43
|
+
// If missing, this workflow is a dynamic workflow.
|
|
44
|
+
string type = 1;
|
|
45
|
+
// An optional workflow description provided by the application.
|
|
46
|
+
// By convention, external tools may interpret its first part,
|
|
47
|
+
// i.e., ending with a line break, as a summary of the description.
|
|
48
|
+
string description = 2;
|
|
49
|
+
repeated WorkflowInteractionDefinition query_definitions = 3;
|
|
50
|
+
repeated WorkflowInteractionDefinition signal_definitions = 4;
|
|
51
|
+
repeated WorkflowInteractionDefinition update_definitions = 5;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// (-- api-linter: core::0123::resource-annotation=disabled
|
|
55
|
+
// aip.dev/not-precedent: The `name` field is optional. --)
|
|
56
|
+
// (-- api-linter: core::0203::optional=disabled --)
|
|
57
|
+
message WorkflowInteractionDefinition {
|
|
58
|
+
// An optional name for the handler. If missing, it represents
|
|
59
|
+
// a dynamic handler that processes any interactions not handled by others.
|
|
60
|
+
// There is at most one dynamic handler per workflow and interaction kind.
|
|
61
|
+
string name = 1;
|
|
62
|
+
// An optional interaction description provided by the application.
|
|
63
|
+
// By convention, external tools may interpret its first part,
|
|
64
|
+
// i.e., ending with a line break, as a summary of the description.
|
|
65
|
+
string description = 2;
|
|
66
|
+
}
|
|
@@ -106,9 +106,13 @@ message ResetPoints {
|
|
|
106
106
|
repeated ResetPointInfo points = 1;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
// ResetPointInfo records the workflow event id that is the first one processed by a given
|
|
110
|
+
// build id or binary checksum. A new reset point will be created if either build id or binary
|
|
111
|
+
// checksum changes (although in general only one or the other will be used at a time).
|
|
109
112
|
message ResetPointInfo {
|
|
110
|
-
//
|
|
111
|
-
|
|
113
|
+
// Worker build id.
|
|
114
|
+
string build_id = 7;
|
|
115
|
+
// A worker binary version identifier (deprecated).
|
|
112
116
|
string binary_checksum = 1;
|
|
113
117
|
// The first run ID in the execution chain that was touched by this worker build.
|
|
114
118
|
string run_id = 2;
|
|
@@ -37,7 +37,7 @@ impl HistoryInfo {
|
|
|
37
37
|
let mut workflow_task_started_event_id = 0;
|
|
38
38
|
let mut wf_task_count = 0;
|
|
39
39
|
let mut history = events.iter().peekable();
|
|
40
|
-
let started_attrs = match &events.
|
|
40
|
+
let started_attrs = match &events.first().unwrap().attributes {
|
|
41
41
|
Some(history_event::Attributes::WorkflowExecutionStartedEventAttributes(attrs)) => {
|
|
42
42
|
attrs.clone()
|
|
43
43
|
}
|
|
@@ -336,7 +336,7 @@ pub mod coresdk {
|
|
|
336
336
|
) -> Option<LocalActivityMarkerData> {
|
|
337
337
|
details
|
|
338
338
|
.get("data")
|
|
339
|
-
.and_then(|p| p.payloads.
|
|
339
|
+
.and_then(|p| p.payloads.first())
|
|
340
340
|
.and_then(|p| std::str::from_utf8(&p.data).ok())
|
|
341
341
|
.and_then(|s| serde_json::from_str(s).ok())
|
|
342
342
|
}
|
|
@@ -35,8 +35,8 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
35
35
|
|
|
36
36
|
// List above OPEN workflow
|
|
37
37
|
let start_time_filter = StartTimeFilter {
|
|
38
|
-
earliest_time: Some(earliest).
|
|
39
|
-
latest_time: Some(latest).
|
|
38
|
+
earliest_time: Some(earliest).map(|t| t.into()),
|
|
39
|
+
latest_time: Some(latest).map(|t| t.into()),
|
|
40
40
|
};
|
|
41
41
|
let filter = ListOpenFilters::ExecutionFilter(WorkflowExecutionFilter {
|
|
42
42
|
workflow_id: wf_name.clone(),
|
|
@@ -63,8 +63,8 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
63
63
|
1,
|
|
64
64
|
Default::default(),
|
|
65
65
|
Some(StartTimeFilter {
|
|
66
|
-
earliest_time: Some(earliest).
|
|
67
|
-
latest_time: Some(latest).
|
|
66
|
+
earliest_time: Some(earliest).map(|t| t.into()),
|
|
67
|
+
latest_time: Some(latest).map(|t| t.into()),
|
|
68
68
|
}),
|
|
69
69
|
Some(ListClosedFilters::ExecutionFilter(
|
|
70
70
|
WorkflowExecutionFilter {
|
|
@@ -35,17 +35,19 @@ use temporal_sdk_core_protos::{
|
|
|
35
35
|
coresdk::{
|
|
36
36
|
activity_result::ActivityExecutionResult,
|
|
37
37
|
workflow_activation::{workflow_activation_job, WorkflowActivation, WorkflowActivationJob},
|
|
38
|
-
workflow_commands::{
|
|
38
|
+
workflow_commands::{
|
|
39
|
+
ActivityCancellationType, FailWorkflowExecution, QueryResult, QuerySuccess, StartTimer,
|
|
40
|
+
},
|
|
39
41
|
workflow_completion::WorkflowActivationCompletion,
|
|
40
42
|
ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
|
|
41
43
|
},
|
|
42
|
-
temporal::api::{failure::v1::Failure, history::v1::history_event},
|
|
44
|
+
temporal::api::{failure::v1::Failure, history::v1::history_event, query::v1::WorkflowQuery},
|
|
43
45
|
};
|
|
44
46
|
use temporal_sdk_core_test_utils::{
|
|
45
47
|
drain_pollers_and_shutdown, history_from_proto_binary, init_core_and_create_wf,
|
|
46
48
|
init_core_replay_preloaded, schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
|
|
47
49
|
};
|
|
48
|
-
use tokio::time::sleep;
|
|
50
|
+
use tokio::{join, time::sleep};
|
|
49
51
|
use uuid::Uuid;
|
|
50
52
|
|
|
51
53
|
// TODO: We should get expected histories for these tests and confirm that the history at the end
|
|
@@ -592,3 +594,139 @@ async fn slow_completes_with_small_cache() {
|
|
|
592
594
|
.await
|
|
593
595
|
.unwrap();
|
|
594
596
|
}
|
|
597
|
+
|
|
598
|
+
#[tokio::test]
|
|
599
|
+
async fn build_id_correct_in_wf_info() {
|
|
600
|
+
let wf_type = "build_id_correct_in_wf_info";
|
|
601
|
+
let mut starter = CoreWfStarter::new(wf_type);
|
|
602
|
+
starter
|
|
603
|
+
.worker_config
|
|
604
|
+
.worker_build_id("1.0")
|
|
605
|
+
.no_remote_activities(true);
|
|
606
|
+
let core = starter.get_worker().await;
|
|
607
|
+
starter.start_wf().await;
|
|
608
|
+
let client = starter.get_client().await;
|
|
609
|
+
let workflow_id = starter.get_task_queue().to_string();
|
|
610
|
+
|
|
611
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
612
|
+
assert_eq!(res.build_id_for_current_task, "1.0");
|
|
613
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
614
|
+
res.run_id.clone(),
|
|
615
|
+
vec![],
|
|
616
|
+
))
|
|
617
|
+
.await
|
|
618
|
+
.unwrap();
|
|
619
|
+
|
|
620
|
+
// Ensure a query on first wft also sees the correct id
|
|
621
|
+
let query_fut = async {
|
|
622
|
+
client
|
|
623
|
+
.query_workflow_execution(
|
|
624
|
+
workflow_id.clone(),
|
|
625
|
+
res.run_id.to_string(),
|
|
626
|
+
WorkflowQuery {
|
|
627
|
+
query_type: "q1".to_string(),
|
|
628
|
+
..Default::default()
|
|
629
|
+
},
|
|
630
|
+
)
|
|
631
|
+
.await
|
|
632
|
+
.unwrap()
|
|
633
|
+
};
|
|
634
|
+
let complete_fut = async {
|
|
635
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
636
|
+
let query = assert_matches!(
|
|
637
|
+
task.jobs.as_slice(),
|
|
638
|
+
[WorkflowActivationJob {
|
|
639
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
640
|
+
}] => q
|
|
641
|
+
);
|
|
642
|
+
assert_eq!(task.build_id_for_current_task, "1.0");
|
|
643
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
644
|
+
task.run_id,
|
|
645
|
+
QueryResult {
|
|
646
|
+
query_id: query.query_id.clone(),
|
|
647
|
+
variant: Some(
|
|
648
|
+
QuerySuccess {
|
|
649
|
+
response: Some("done".into()),
|
|
650
|
+
}
|
|
651
|
+
.into(),
|
|
652
|
+
),
|
|
653
|
+
}
|
|
654
|
+
.into(),
|
|
655
|
+
))
|
|
656
|
+
.await
|
|
657
|
+
.unwrap();
|
|
658
|
+
};
|
|
659
|
+
join!(query_fut, complete_fut);
|
|
660
|
+
starter.shutdown().await;
|
|
661
|
+
client
|
|
662
|
+
.reset_sticky_task_queue(workflow_id.clone(), "".to_string())
|
|
663
|
+
.await
|
|
664
|
+
.unwrap();
|
|
665
|
+
|
|
666
|
+
let mut starter = starter.clone_no_worker();
|
|
667
|
+
starter.worker_config.worker_build_id("2.0");
|
|
668
|
+
let core = starter.get_worker().await;
|
|
669
|
+
|
|
670
|
+
let query_fut = async {
|
|
671
|
+
client
|
|
672
|
+
.query_workflow_execution(
|
|
673
|
+
workflow_id.clone(),
|
|
674
|
+
res.run_id.to_string(),
|
|
675
|
+
WorkflowQuery {
|
|
676
|
+
query_type: "q2".to_string(),
|
|
677
|
+
..Default::default()
|
|
678
|
+
},
|
|
679
|
+
)
|
|
680
|
+
.await
|
|
681
|
+
.unwrap()
|
|
682
|
+
};
|
|
683
|
+
let complete_fut = async {
|
|
684
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
685
|
+
assert_eq!(res.build_id_for_current_task, "1.0");
|
|
686
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
687
|
+
res.run_id.clone(),
|
|
688
|
+
vec![],
|
|
689
|
+
))
|
|
690
|
+
.await
|
|
691
|
+
.unwrap();
|
|
692
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
693
|
+
let query = assert_matches!(
|
|
694
|
+
task.jobs.as_slice(),
|
|
695
|
+
[WorkflowActivationJob {
|
|
696
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
697
|
+
}] => q
|
|
698
|
+
);
|
|
699
|
+
assert_eq!(task.build_id_for_current_task, "1.0");
|
|
700
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
701
|
+
task.run_id,
|
|
702
|
+
QueryResult {
|
|
703
|
+
query_id: query.query_id.clone(),
|
|
704
|
+
variant: Some(
|
|
705
|
+
QuerySuccess {
|
|
706
|
+
response: Some("done".into()),
|
|
707
|
+
}
|
|
708
|
+
.into(),
|
|
709
|
+
),
|
|
710
|
+
}
|
|
711
|
+
.into(),
|
|
712
|
+
))
|
|
713
|
+
.await
|
|
714
|
+
.unwrap();
|
|
715
|
+
};
|
|
716
|
+
join!(query_fut, complete_fut);
|
|
717
|
+
|
|
718
|
+
client
|
|
719
|
+
.signal_workflow_execution(
|
|
720
|
+
workflow_id.clone(),
|
|
721
|
+
"".to_string(),
|
|
722
|
+
"whatever".to_string(),
|
|
723
|
+
None,
|
|
724
|
+
None,
|
|
725
|
+
)
|
|
726
|
+
.await
|
|
727
|
+
.unwrap();
|
|
728
|
+
|
|
729
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
730
|
+
assert_eq!(res.build_id_for_current_task, "2.0");
|
|
731
|
+
core.complete_execution(&res.run_id).await;
|
|
732
|
+
}
|