@temporalio/core-bridge 0.19.2 → 0.20.2
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 +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +207 -108
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +139 -151
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
|
@@ -7,9 +7,11 @@ mod determinism;
|
|
|
7
7
|
mod local_activities;
|
|
8
8
|
mod patches;
|
|
9
9
|
mod replay;
|
|
10
|
+
mod resets;
|
|
10
11
|
mod signals;
|
|
11
12
|
mod stickyness;
|
|
12
13
|
mod timers;
|
|
14
|
+
mod upsert_search_attrs;
|
|
13
15
|
|
|
14
16
|
use assert_matches::assert_matches;
|
|
15
17
|
use futures::{channel::mpsc::UnboundedReceiver, future, SinkExt, StreamExt};
|
|
@@ -21,8 +23,9 @@ use std::{
|
|
|
21
23
|
},
|
|
22
24
|
time::Duration,
|
|
23
25
|
};
|
|
26
|
+
use temporal_client::{WorkflowClientTrait, WorkflowOptions};
|
|
24
27
|
use temporal_sdk::{WfContext, WorkflowResult};
|
|
25
|
-
use temporal_sdk_core_api::{errors::PollWfError,
|
|
28
|
+
use temporal_sdk_core_api::{errors::PollWfError, Worker};
|
|
26
29
|
use temporal_sdk_core_protos::{
|
|
27
30
|
coresdk::{
|
|
28
31
|
activity_result::ActivityExecutionResult,
|
|
@@ -35,7 +38,7 @@ use temporal_sdk_core_protos::{
|
|
|
35
38
|
};
|
|
36
39
|
use temporal_sdk_core_test_utils::{
|
|
37
40
|
history_from_proto_binary, init_core_and_create_wf, init_core_replay_preloaded,
|
|
38
|
-
schedule_activity_cmd,
|
|
41
|
+
schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
|
|
39
42
|
};
|
|
40
43
|
use tokio::time::sleep;
|
|
41
44
|
use uuid::Uuid;
|
|
@@ -46,19 +49,18 @@ use uuid::Uuid;
|
|
|
46
49
|
#[tokio::test]
|
|
47
50
|
async fn parallel_workflows_same_queue() {
|
|
48
51
|
let mut starter = CoreWfStarter::new("parallel_workflows_same_queue");
|
|
49
|
-
let core = starter.
|
|
50
|
-
let task_q = starter.get_task_queue().to_string();
|
|
52
|
+
let core = starter.get_worker().await;
|
|
51
53
|
let num_workflows = 25usize;
|
|
52
54
|
|
|
53
55
|
let run_ids: Vec<_> = future::join_all(
|
|
54
|
-
(0..num_workflows)
|
|
56
|
+
(0..num_workflows)
|
|
57
|
+
.map(|i| starter.start_wf_with_id(format!("wf-id-{}", i), WorkflowOptions::default())),
|
|
55
58
|
)
|
|
56
59
|
.await;
|
|
57
60
|
|
|
58
61
|
let mut send_chans = HashMap::new();
|
|
59
62
|
async fn wf_task(
|
|
60
|
-
|
|
61
|
-
task_q: String,
|
|
63
|
+
worker: Arc<dyn Worker>,
|
|
62
64
|
mut task_chan: UnboundedReceiver<WorkflowActivation>,
|
|
63
65
|
) {
|
|
64
66
|
let task = task_chan.next().await.unwrap();
|
|
@@ -68,10 +70,11 @@ async fn parallel_workflows_same_queue() {
|
|
|
68
70
|
variant: Some(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
69
71
|
}]
|
|
70
72
|
);
|
|
71
|
-
|
|
73
|
+
worker
|
|
74
|
+
.complete_timer(&task.run_id, 1, Duration::from_secs(1))
|
|
72
75
|
.await;
|
|
73
76
|
let task = task_chan.next().await.unwrap();
|
|
74
|
-
|
|
77
|
+
worker.complete_execution(&task.run_id).await;
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
let handles: Vec<_> = run_ids
|
|
@@ -79,12 +82,12 @@ async fn parallel_workflows_same_queue() {
|
|
|
79
82
|
.map(|run_id| {
|
|
80
83
|
let (tx, rx) = futures::channel::mpsc::unbounded();
|
|
81
84
|
send_chans.insert(run_id.clone(), tx);
|
|
82
|
-
tokio::spawn(wf_task(core.clone(),
|
|
85
|
+
tokio::spawn(wf_task(core.clone(), rx))
|
|
83
86
|
})
|
|
84
87
|
.collect();
|
|
85
88
|
|
|
86
89
|
for _ in 0..num_workflows * 2 {
|
|
87
|
-
let task = core.poll_workflow_activation(
|
|
90
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
88
91
|
send_chans
|
|
89
92
|
.get(&task.run_id)
|
|
90
93
|
.unwrap()
|
|
@@ -120,6 +123,7 @@ async fn workflow_lru_cache_evictions() {
|
|
|
120
123
|
format!("wce-{}", Uuid::new_v4()),
|
|
121
124
|
wf_type.to_string(),
|
|
122
125
|
vec![],
|
|
126
|
+
WorkflowOptions::default(),
|
|
123
127
|
)
|
|
124
128
|
.await
|
|
125
129
|
.unwrap();
|
|
@@ -136,8 +140,7 @@ async fn workflow_lru_cache_evictions() {
|
|
|
136
140
|
#[tokio::test]
|
|
137
141
|
async fn shutdown_aborts_actively_blocked_poll() {
|
|
138
142
|
let mut starter = CoreWfStarter::new("shutdown_aborts_actively_blocked_poll");
|
|
139
|
-
let core = starter.
|
|
140
|
-
let task_q = starter.get_task_queue();
|
|
143
|
+
let core = starter.get_worker().await;
|
|
141
144
|
// Begin the poll, and request shutdown from another thread after a small period of time.
|
|
142
145
|
let tcore = core.clone();
|
|
143
146
|
let handle = tokio::spawn(async move {
|
|
@@ -145,14 +148,14 @@ async fn shutdown_aborts_actively_blocked_poll() {
|
|
|
145
148
|
tcore.shutdown().await;
|
|
146
149
|
});
|
|
147
150
|
assert_matches!(
|
|
148
|
-
core.poll_workflow_activation(
|
|
151
|
+
core.poll_workflow_activation().await.unwrap_err(),
|
|
149
152
|
PollWfError::ShutDown
|
|
150
153
|
);
|
|
151
154
|
handle.await.unwrap();
|
|
152
155
|
// Ensure double-shutdown doesn't explode
|
|
153
156
|
core.shutdown().await;
|
|
154
157
|
assert_matches!(
|
|
155
|
-
core.poll_workflow_activation(
|
|
158
|
+
core.poll_workflow_activation().await.unwrap_err(),
|
|
156
159
|
PollWfError::ShutDown
|
|
157
160
|
);
|
|
158
161
|
}
|
|
@@ -160,25 +163,26 @@ async fn shutdown_aborts_actively_blocked_poll() {
|
|
|
160
163
|
#[rstest::rstest]
|
|
161
164
|
#[tokio::test]
|
|
162
165
|
async fn fail_wf_task(#[values(true, false)] replay: bool) {
|
|
163
|
-
let
|
|
164
|
-
init_core_replay_preloaded(
|
|
166
|
+
let core = if replay {
|
|
167
|
+
let (core, _) = init_core_replay_preloaded(
|
|
165
168
|
"fail_wf_task",
|
|
166
169
|
&history_from_proto_binary("histories/fail_wf_task.bin")
|
|
167
170
|
.await
|
|
168
171
|
.unwrap(),
|
|
169
|
-
)
|
|
172
|
+
);
|
|
173
|
+
core
|
|
170
174
|
} else {
|
|
171
|
-
init_core_and_create_wf("fail_wf_task").await
|
|
175
|
+
let mut starter = init_core_and_create_wf("fail_wf_task").await;
|
|
176
|
+
starter.get_worker().await
|
|
172
177
|
};
|
|
173
178
|
// Start with a timer
|
|
174
|
-
let task = core.poll_workflow_activation(
|
|
175
|
-
core.complete_timer(&
|
|
179
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
180
|
+
core.complete_timer(&task.run_id, 0, Duration::from_millis(200))
|
|
176
181
|
.await;
|
|
177
182
|
|
|
178
183
|
// Then break for whatever reason
|
|
179
|
-
let task = core.poll_workflow_activation(
|
|
184
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
180
185
|
core.complete_workflow_activation(WorkflowActivationCompletion::fail(
|
|
181
|
-
&task_q,
|
|
182
186
|
task.run_id,
|
|
183
187
|
Failure::application_failure("I did an oopsie".to_string(), false),
|
|
184
188
|
))
|
|
@@ -187,7 +191,7 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
|
|
|
187
191
|
|
|
188
192
|
// The server will want to retry the task. This time we finish the workflow -- but we need
|
|
189
193
|
// to poll a couple of times as there will be more than one required workflow activation.
|
|
190
|
-
let task = core.poll_workflow_activation(
|
|
194
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
191
195
|
// The first poll response will tell us to evict
|
|
192
196
|
assert_matches!(
|
|
193
197
|
task.jobs.as_slice(),
|
|
@@ -195,13 +199,12 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
|
|
|
195
199
|
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
196
200
|
}]
|
|
197
201
|
);
|
|
198
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::empty(
|
|
202
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
199
203
|
.await
|
|
200
204
|
.unwrap();
|
|
201
205
|
|
|
202
|
-
let task = core.poll_workflow_activation(
|
|
206
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
203
207
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
204
|
-
&task_q,
|
|
205
208
|
task.run_id,
|
|
206
209
|
vec![StartTimer {
|
|
207
210
|
seq: 0,
|
|
@@ -211,19 +214,21 @@ async fn fail_wf_task(#[values(true, false)] replay: bool) {
|
|
|
211
214
|
))
|
|
212
215
|
.await
|
|
213
216
|
.unwrap();
|
|
214
|
-
let task = core.poll_workflow_activation(
|
|
215
|
-
core.complete_execution(&
|
|
217
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
218
|
+
core.complete_execution(&task.run_id).await;
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
#[tokio::test]
|
|
219
222
|
async fn fail_workflow_execution() {
|
|
220
|
-
let
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
let core = init_core_and_create_wf("fail_workflow_execution")
|
|
224
|
+
.await
|
|
225
|
+
.get_worker()
|
|
226
|
+
.await;
|
|
227
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
228
|
+
core.complete_timer(&task.run_id, 0, Duration::from_secs(1))
|
|
223
229
|
.await;
|
|
224
|
-
let task = core.poll_workflow_activation(
|
|
230
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
225
231
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
226
|
-
&task_q,
|
|
227
232
|
task.run_id,
|
|
228
233
|
vec![FailWorkflowExecution {
|
|
229
234
|
failure: Some(Failure::application_failure("I'm ded".to_string(), false)),
|
|
@@ -236,15 +241,16 @@ async fn fail_workflow_execution() {
|
|
|
236
241
|
|
|
237
242
|
#[tokio::test]
|
|
238
243
|
async fn signal_workflow() {
|
|
239
|
-
let
|
|
240
|
-
let
|
|
244
|
+
let mut starter = init_core_and_create_wf("signal_workflow").await;
|
|
245
|
+
let core = starter.get_worker().await;
|
|
246
|
+
let client = starter.get_client().await;
|
|
247
|
+
let workflow_id = starter.get_task_queue().to_string();
|
|
241
248
|
|
|
242
249
|
let signal_id_1 = "signal1";
|
|
243
250
|
let signal_id_2 = "signal2";
|
|
244
|
-
let res = core.poll_workflow_activation(
|
|
251
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
245
252
|
// Task is completed with no commands
|
|
246
253
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
247
|
-
&task_q,
|
|
248
254
|
res.run_id.clone(),
|
|
249
255
|
vec![],
|
|
250
256
|
))
|
|
@@ -252,7 +258,7 @@ async fn signal_workflow() {
|
|
|
252
258
|
.unwrap();
|
|
253
259
|
|
|
254
260
|
// Send the signals to the server
|
|
255
|
-
|
|
261
|
+
client
|
|
256
262
|
.signal_workflow_execution(
|
|
257
263
|
workflow_id.to_string(),
|
|
258
264
|
res.run_id.to_string(),
|
|
@@ -261,7 +267,7 @@ async fn signal_workflow() {
|
|
|
261
267
|
)
|
|
262
268
|
.await
|
|
263
269
|
.unwrap();
|
|
264
|
-
|
|
270
|
+
client
|
|
265
271
|
.signal_workflow_execution(
|
|
266
272
|
workflow_id.to_string(),
|
|
267
273
|
res.run_id.to_string(),
|
|
@@ -271,7 +277,7 @@ async fn signal_workflow() {
|
|
|
271
277
|
.await
|
|
272
278
|
.unwrap();
|
|
273
279
|
|
|
274
|
-
let mut res = core.poll_workflow_activation(
|
|
280
|
+
let mut res = core.poll_workflow_activation().await.unwrap();
|
|
275
281
|
// Sometimes both signals are complete at once, sometimes only one, depending on server
|
|
276
282
|
// Converting test to wf function type would make this shorter
|
|
277
283
|
if res.jobs.len() == 2 {
|
|
@@ -294,13 +300,12 @@ async fn signal_workflow() {
|
|
|
294
300
|
},]
|
|
295
301
|
);
|
|
296
302
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
297
|
-
&task_q,
|
|
298
303
|
res.run_id,
|
|
299
304
|
vec![],
|
|
300
305
|
))
|
|
301
306
|
.await
|
|
302
307
|
.unwrap();
|
|
303
|
-
res = core.poll_workflow_activation(
|
|
308
|
+
res = core.poll_workflow_activation().await.unwrap();
|
|
304
309
|
assert_matches!(
|
|
305
310
|
res.jobs.as_slice(),
|
|
306
311
|
[WorkflowActivationJob {
|
|
@@ -308,20 +313,20 @@ async fn signal_workflow() {
|
|
|
308
313
|
},]
|
|
309
314
|
);
|
|
310
315
|
}
|
|
311
|
-
core.complete_execution(&
|
|
316
|
+
core.complete_execution(&res.run_id).await;
|
|
312
317
|
}
|
|
313
318
|
|
|
314
319
|
#[tokio::test]
|
|
315
320
|
async fn signal_workflow_signal_not_handled_on_workflow_completion() {
|
|
316
|
-
let
|
|
321
|
+
let mut starter =
|
|
317
322
|
init_core_and_create_wf("signal_workflow_signal_not_handled_on_workflow_completion").await;
|
|
318
|
-
let
|
|
323
|
+
let core = starter.get_worker().await;
|
|
324
|
+
let workflow_id = starter.get_task_queue().to_string();
|
|
319
325
|
let signal_id_1 = "signal1";
|
|
320
326
|
for i in 1..=2 {
|
|
321
|
-
let res = core.poll_workflow_activation(
|
|
327
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
322
328
|
// Task is completed with a timer
|
|
323
329
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
324
|
-
&task_q,
|
|
325
330
|
res.run_id,
|
|
326
331
|
vec![StartTimer {
|
|
327
332
|
seq: 0,
|
|
@@ -332,7 +337,7 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
|
|
|
332
337
|
.await
|
|
333
338
|
.unwrap();
|
|
334
339
|
|
|
335
|
-
let res = core.poll_workflow_activation(
|
|
340
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
336
341
|
|
|
337
342
|
if i == 1 {
|
|
338
343
|
// First attempt we should only see the timer being fired
|
|
@@ -346,9 +351,11 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
|
|
|
346
351
|
let run_id = res.run_id.clone();
|
|
347
352
|
|
|
348
353
|
// Send the signal to the server
|
|
349
|
-
|
|
354
|
+
starter
|
|
355
|
+
.get_client()
|
|
356
|
+
.await
|
|
350
357
|
.signal_workflow_execution(
|
|
351
|
-
workflow_id.
|
|
358
|
+
workflow_id.clone(),
|
|
352
359
|
res.run_id.to_string(),
|
|
353
360
|
signal_id_1.to_string(),
|
|
354
361
|
None,
|
|
@@ -358,22 +365,19 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
|
|
|
358
365
|
|
|
359
366
|
// Send completion - not having seen a poll response with a signal in it yet (unhandled
|
|
360
367
|
// command error will be logged as a warning and an eviction will be issued)
|
|
361
|
-
core.complete_execution(&
|
|
368
|
+
core.complete_execution(&run_id).await;
|
|
362
369
|
|
|
363
370
|
// We should be told to evict
|
|
364
|
-
let res = core.poll_workflow_activation(
|
|
371
|
+
let res = core.poll_workflow_activation().await.unwrap();
|
|
365
372
|
assert_matches!(
|
|
366
373
|
res.jobs.as_slice(),
|
|
367
374
|
[WorkflowActivationJob {
|
|
368
375
|
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
369
376
|
}]
|
|
370
377
|
);
|
|
371
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::empty(
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
))
|
|
375
|
-
.await
|
|
376
|
-
.unwrap();
|
|
378
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
|
|
379
|
+
.await
|
|
380
|
+
.unwrap();
|
|
377
381
|
// Loop to the top to handle wf from the beginning
|
|
378
382
|
continue;
|
|
379
383
|
}
|
|
@@ -390,7 +394,7 @@ async fn signal_workflow_signal_not_handled_on_workflow_completion() {
|
|
|
390
394
|
}
|
|
391
395
|
]
|
|
392
396
|
);
|
|
393
|
-
core.complete_execution(&
|
|
397
|
+
core.complete_execution(&res.run_id).await;
|
|
394
398
|
}
|
|
395
399
|
}
|
|
396
400
|
|
|
@@ -404,13 +408,14 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
404
408
|
// Test needs eviction on and a short timeout
|
|
405
409
|
.max_cached_workflows(0usize)
|
|
406
410
|
.wft_timeout(Duration::from_secs(1));
|
|
407
|
-
let core = wf_starter.
|
|
411
|
+
let core = wf_starter.get_worker().await;
|
|
412
|
+
let client = wf_starter.get_client().await;
|
|
408
413
|
let task_q = wf_starter.get_task_queue();
|
|
409
414
|
let wf_id = &wf_starter.get_wf_id().to_owned();
|
|
410
415
|
|
|
411
416
|
// Set up some helpers for polling and completing
|
|
412
417
|
let poll_sched_act = || async {
|
|
413
|
-
let wf_task = core.poll_workflow_activation(
|
|
418
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
414
419
|
core.complete_workflow_activation(
|
|
415
420
|
schedule_activity_cmd(
|
|
416
421
|
0,
|
|
@@ -420,7 +425,7 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
420
425
|
Duration::from_secs(60),
|
|
421
426
|
Duration::from_secs(60),
|
|
422
427
|
)
|
|
423
|
-
.into_completion(
|
|
428
|
+
.into_completion(wf_task.run_id.clone()),
|
|
424
429
|
)
|
|
425
430
|
.await
|
|
426
431
|
.unwrap();
|
|
@@ -428,7 +433,7 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
428
433
|
};
|
|
429
434
|
let poll_sched_act_poll = || async {
|
|
430
435
|
poll_sched_act().await;
|
|
431
|
-
let wf_task = core.poll_workflow_activation(
|
|
436
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
432
437
|
assert_matches!(
|
|
433
438
|
wf_task.jobs.as_slice(),
|
|
434
439
|
[
|
|
@@ -452,36 +457,35 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
452
457
|
let wf_task = poll_sched_act().await;
|
|
453
458
|
// Before polling for a task again, we start and complete the activity and send the
|
|
454
459
|
// corresponding signals.
|
|
455
|
-
let ac_task = core.poll_activity_task(
|
|
460
|
+
let ac_task = core.poll_activity_task().await.unwrap();
|
|
456
461
|
let rid = wf_task.run_id.clone();
|
|
457
462
|
// Send the signals to the server & resolve activity -- sometimes this happens too fast
|
|
458
463
|
sleep(Duration::from_millis(200)).await;
|
|
459
|
-
|
|
464
|
+
client
|
|
460
465
|
.signal_workflow_execution(wf_id.to_string(), rid, signal_at_start.to_string(), None)
|
|
461
466
|
.await
|
|
462
467
|
.unwrap();
|
|
463
468
|
// Complete activity successfully.
|
|
464
469
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
465
470
|
task_token: ac_task.task_token,
|
|
466
|
-
task_queue: task_q.to_string(),
|
|
467
471
|
result: Some(ActivityExecutionResult::ok(Default::default())),
|
|
468
472
|
})
|
|
469
473
|
.await
|
|
470
474
|
.unwrap();
|
|
471
475
|
let rid = wf_task.run_id.clone();
|
|
472
|
-
|
|
476
|
+
client
|
|
473
477
|
.signal_workflow_execution(wf_id.to_string(), rid, signal_at_complete.to_string(), None)
|
|
474
478
|
.await
|
|
475
479
|
.unwrap();
|
|
476
480
|
// Now poll again, it will be an eviction b/c non-sticky mode.
|
|
477
|
-
let wf_task = core.poll_workflow_activation(
|
|
481
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
478
482
|
assert_matches!(
|
|
479
483
|
wf_task.jobs.as_slice(),
|
|
480
484
|
[WorkflowActivationJob {
|
|
481
485
|
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
482
486
|
}]
|
|
483
487
|
);
|
|
484
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::empty(
|
|
488
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
485
489
|
.await
|
|
486
490
|
.unwrap();
|
|
487
491
|
// Start from the beginning
|
|
@@ -491,11 +495,11 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
491
495
|
// Poll again, which should not have any work to do and spin, until the complete goes through.
|
|
492
496
|
// Which will be rejected with not found, producing an eviction.
|
|
493
497
|
let (wf_task, _) = tokio::join!(
|
|
494
|
-
async { core.poll_workflow_activation(
|
|
498
|
+
async { core.poll_workflow_activation().await.unwrap() },
|
|
495
499
|
async {
|
|
496
500
|
sleep(Duration::from_millis(500)).await;
|
|
497
501
|
// Reply to the first one, finally
|
|
498
|
-
core.complete_execution(
|
|
502
|
+
core.complete_execution(&wf_task.run_id).await;
|
|
499
503
|
}
|
|
500
504
|
);
|
|
501
505
|
assert_matches!(
|
|
@@ -504,10 +508,10 @@ async fn wft_timeout_doesnt_create_unsolvable_autocomplete() {
|
|
|
504
508
|
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
505
509
|
}]
|
|
506
510
|
);
|
|
507
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::empty(
|
|
511
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
508
512
|
.await
|
|
509
513
|
.unwrap();
|
|
510
514
|
// Do it all over again, without timing out this time
|
|
511
515
|
let wf_task = poll_sched_act_poll().await;
|
|
512
|
-
core.complete_execution(
|
|
516
|
+
core.complete_execution(&wf_task.run_id).await;
|
|
513
517
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use futures::future::join_all;
|
|
3
3
|
use std::time::{Duration, Instant};
|
|
4
|
+
use temporal_client::WorkflowOptions;
|
|
4
5
|
use temporal_sdk::{ActivityOptions, WfContext};
|
|
5
6
|
use temporal_sdk_core_protos::coresdk::{
|
|
6
7
|
activity_result::ActivityExecutionResult, activity_task::activity_task as act_task,
|
|
@@ -19,7 +20,6 @@ async fn activity_load() {
|
|
|
19
20
|
.max_at_polls(10)
|
|
20
21
|
.max_at(CONCURRENCY);
|
|
21
22
|
let mut worker = starter.worker().await;
|
|
22
|
-
let task_q = starter.get_task_queue().to_owned();
|
|
23
23
|
|
|
24
24
|
let activity_id = "act-1";
|
|
25
25
|
let activity_timeout = Duration::from_secs(8);
|
|
@@ -57,7 +57,12 @@ async fn activity_load() {
|
|
|
57
57
|
let wf_id = format!("activity_load_{}", i);
|
|
58
58
|
async move {
|
|
59
59
|
worker
|
|
60
|
-
.submit_wf(
|
|
60
|
+
.submit_wf(
|
|
61
|
+
wf_id,
|
|
62
|
+
wf_type.to_owned(),
|
|
63
|
+
vec![],
|
|
64
|
+
WorkflowOptions::default(),
|
|
65
|
+
)
|
|
61
66
|
.await
|
|
62
67
|
.unwrap();
|
|
63
68
|
}
|
|
@@ -66,15 +71,14 @@ async fn activity_load() {
|
|
|
66
71
|
dbg!(starting.elapsed());
|
|
67
72
|
|
|
68
73
|
let running = Instant::now();
|
|
69
|
-
let core = starter.
|
|
74
|
+
let core = starter.get_worker().await;
|
|
70
75
|
|
|
71
76
|
// Poll for and complete all activities
|
|
72
77
|
let c2 = core.clone();
|
|
73
78
|
let all_acts = async move {
|
|
74
79
|
let mut act_complete_futs = vec![];
|
|
75
80
|
for _ in 0..CONCURRENCY {
|
|
76
|
-
let
|
|
77
|
-
let task = c2.poll_activity_task(&task_q).await.unwrap();
|
|
81
|
+
let task = c2.poll_activity_task().await.unwrap();
|
|
78
82
|
assert_matches!(
|
|
79
83
|
task.variant,
|
|
80
84
|
Some(act_task::Variant::Start(ref start_activity)) => {
|
|
@@ -86,7 +90,6 @@ async fn activity_load() {
|
|
|
86
90
|
act_complete_futs.push(tokio::spawn(async move {
|
|
87
91
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
88
92
|
task_token: task.task_token,
|
|
89
|
-
task_queue: task_q,
|
|
90
93
|
result: Some(ActivityExecutionResult::ok(pd.into())),
|
|
91
94
|
})
|
|
92
95
|
.await
|
package/sdk-core/tests/main.rs
CHANGED
|
@@ -2,19 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
#[cfg(test)]
|
|
4
4
|
mod integ_tests {
|
|
5
|
-
use std::str::FromStr;
|
|
6
|
-
use temporal_sdk_core::{
|
|
7
|
-
ClientTlsConfig, ServerGatewayApis, ServerGatewayOptionsBuilder, TlsConfig,
|
|
8
|
-
};
|
|
9
|
-
use temporal_sdk_core_test_utils::NAMESPACE;
|
|
10
|
-
use url::Url;
|
|
11
|
-
|
|
12
5
|
mod client_tests;
|
|
13
6
|
mod heartbeat_tests;
|
|
14
7
|
mod polling_tests;
|
|
15
8
|
mod queries_tests;
|
|
16
9
|
mod workflow_tests;
|
|
17
10
|
|
|
11
|
+
use std::str::FromStr;
|
|
12
|
+
use temporal_client::WorkflowService;
|
|
13
|
+
use temporal_sdk_core::{
|
|
14
|
+
init_worker, telemetry_init, ClientOptionsBuilder, ClientTlsConfig, TlsConfig,
|
|
15
|
+
WorkflowClientTrait,
|
|
16
|
+
};
|
|
17
|
+
use temporal_sdk_core_api::{worker::WorkerConfigBuilder, CoreTelemetry};
|
|
18
|
+
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::ListNamespacesRequest;
|
|
19
|
+
use temporal_sdk_core_test_utils::{
|
|
20
|
+
get_integ_server_options, get_integ_telem_options, NAMESPACE,
|
|
21
|
+
};
|
|
22
|
+
use url::Url;
|
|
23
|
+
|
|
24
|
+
// Create a worker like a bridge would (unwraps aside)
|
|
25
|
+
#[tokio::test]
|
|
26
|
+
#[ignore] // Really a compile time check more than anything
|
|
27
|
+
async fn lang_bridge_example() {
|
|
28
|
+
let opts = get_integ_server_options();
|
|
29
|
+
let telem_d = telemetry_init(&get_integ_telem_options()).unwrap();
|
|
30
|
+
let mut retrying_client = opts
|
|
31
|
+
.connect_no_namespace(telem_d.get_metric_meter())
|
|
32
|
+
.await
|
|
33
|
+
.unwrap();
|
|
34
|
+
|
|
35
|
+
let _worker = init_worker(
|
|
36
|
+
WorkerConfigBuilder::default()
|
|
37
|
+
.namespace("default")
|
|
38
|
+
.task_queue("Wheee!")
|
|
39
|
+
.build()
|
|
40
|
+
.unwrap(),
|
|
41
|
+
// clone the client if you intend to use it later. Strip off the retry wrapper since
|
|
42
|
+
// worker will assert its own
|
|
43
|
+
retrying_client.clone(),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Do things with worker or client
|
|
47
|
+
let _ = retrying_client
|
|
48
|
+
.list_namespaces(ListNamespacesRequest::default())
|
|
49
|
+
.await;
|
|
50
|
+
}
|
|
51
|
+
|
|
18
52
|
// TODO: Currently ignored because starting up the docker image with TLS requires some hoop
|
|
19
53
|
// jumping. We should upgrade CI to be able to do that but this was manually run against
|
|
20
54
|
// https://github.com/temporalio/customization-samples/tree/master/tls/tls-simple
|
|
@@ -37,9 +71,8 @@ mod integ_tests {
|
|
|
37
71
|
)
|
|
38
72
|
.await
|
|
39
73
|
.unwrap();
|
|
40
|
-
let sgo =
|
|
74
|
+
let sgo = ClientOptionsBuilder::default()
|
|
41
75
|
.target_url(Url::from_str("https://localhost:7233").unwrap())
|
|
42
|
-
.namespace(NAMESPACE.to_string())
|
|
43
76
|
.worker_binary_id("binident".to_string())
|
|
44
77
|
.tls_cfg(TlsConfig {
|
|
45
78
|
server_root_ca_cert: Some(root),
|
|
@@ -51,7 +84,7 @@ mod integ_tests {
|
|
|
51
84
|
})
|
|
52
85
|
.build()
|
|
53
86
|
.unwrap();
|
|
54
|
-
let con = sgo.connect(None).await.unwrap();
|
|
87
|
+
let con = sgo.connect(NAMESPACE.to_string(), None).await.unwrap();
|
|
55
88
|
con.list_namespaces().await.unwrap();
|
|
56
89
|
}
|
|
57
90
|
}
|
package/src/conversions.rs
CHANGED
|
@@ -9,8 +9,8 @@ use opentelemetry::trace::{SpanContext, SpanId, TraceFlags, TraceId, TraceState}
|
|
|
9
9
|
use std::{fmt::Display, net::SocketAddr, str::FromStr, time::Duration};
|
|
10
10
|
use temporal_sdk_core::{
|
|
11
11
|
api::worker::{WorkerConfig, WorkerConfigBuilder},
|
|
12
|
-
ClientTlsConfig, RetryConfig,
|
|
13
|
-
|
|
12
|
+
ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryConfig, TelemetryOptions,
|
|
13
|
+
TelemetryOptionsBuilder, TlsConfig, Url,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
macro_rules! js_value_getter {
|
|
@@ -105,10 +105,7 @@ where
|
|
|
105
105
|
|
|
106
106
|
pub(crate) trait ObjectHandleConversionsExt {
|
|
107
107
|
fn as_otel_span_context(&self, ctx: &mut FunctionContext) -> NeonResult<SpanContext>;
|
|
108
|
-
fn
|
|
109
|
-
&self,
|
|
110
|
-
ctx: &mut FunctionContext,
|
|
111
|
-
) -> NeonResult<ServerGatewayOptions>;
|
|
108
|
+
fn as_client_options(&self, ctx: &mut FunctionContext) -> NeonResult<ClientOptions>;
|
|
112
109
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemetryOptions>;
|
|
113
110
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig>;
|
|
114
111
|
}
|
|
@@ -127,10 +124,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
127
124
|
))
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
fn
|
|
131
|
-
&self,
|
|
132
|
-
cx: &mut FunctionContext,
|
|
133
|
-
) -> NeonResult<ServerGatewayOptions> {
|
|
127
|
+
fn as_client_options(&self, cx: &mut FunctionContext) -> NeonResult<ClientOptions> {
|
|
134
128
|
let url = match Url::parse(&js_value_getter!(cx, self, "url", JsString)) {
|
|
135
129
|
Ok(url) => url,
|
|
136
130
|
// Note that address is what's used in the Node side.
|
|
@@ -204,7 +198,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
204
198
|
},
|
|
205
199
|
};
|
|
206
200
|
|
|
207
|
-
let mut gateway_opts =
|
|
201
|
+
let mut gateway_opts = ClientOptionsBuilder::default();
|
|
208
202
|
if let Some(tls_cfg) = tls_cfg {
|
|
209
203
|
gateway_opts.tls_cfg(tls_cfg);
|
|
210
204
|
}
|
|
@@ -212,7 +206,6 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
212
206
|
.client_name("temporal-typescript".to_string())
|
|
213
207
|
.client_version(js_value_getter!(cx, self, "sdkVersion", JsString))
|
|
214
208
|
.target_url(url)
|
|
215
|
-
.namespace(js_value_getter!(cx, self, "namespace", JsString))
|
|
216
209
|
.identity(js_value_getter!(cx, self, "identity", JsString))
|
|
217
210
|
.worker_binary_id(js_value_getter!(cx, self, "workerBinaryId", JsString))
|
|
218
211
|
.retry_config(retry_config)
|
|
@@ -255,6 +248,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
255
248
|
}
|
|
256
249
|
|
|
257
250
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig> {
|
|
251
|
+
let namespace = js_value_getter!(cx, self, "namespace", JsString);
|
|
258
252
|
let task_queue = js_value_getter!(cx, self, "taskQueue", JsString);
|
|
259
253
|
let max_outstanding_activities =
|
|
260
254
|
js_value_getter!(cx, self, "maxConcurrentActivityTaskExecutions", JsNumber) as usize;
|
|
@@ -298,6 +292,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
298
292
|
.max_cached_workflows(max_cached_workflows)
|
|
299
293
|
.nonsticky_to_sticky_poll_ratio(nonsticky_to_sticky_poll_ratio)
|
|
300
294
|
.sticky_queue_schedule_to_start_timeout(sticky_queue_schedule_to_start_timeout)
|
|
295
|
+
.namespace(namespace)
|
|
301
296
|
.task_queue(task_queue)
|
|
302
297
|
.max_heartbeat_throttle_interval(max_heartbeat_throttle_interval)
|
|
303
298
|
.default_heartbeat_throttle_interval(default_heartbeat_throttle_interval)
|