@temporalio/core-bridge 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +520 -456
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +8 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +1 -1
- package/sdk-core/.github/workflows/heavy.yml +1 -0
- package/sdk-core/README.md +13 -7
- package/sdk-core/client/src/lib.rs +27 -9
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +3 -3
- package/sdk-core/core/Cargo.toml +3 -4
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +197 -18
- package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +212 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
- package/sdk-core/core/src/core_tests/queries.rs +32 -14
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
- package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
- package/sdk-core/core/src/internal_flags.rs +141 -0
- package/sdk-core/core/src/lib.rs +14 -9
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +38 -14
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +65 -13
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
- package/sdk-core/core/src/worker/activities.rs +347 -173
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +137 -44
- package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
- package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
- package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
- package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
- package/sdk-core/core-api/Cargo.toml +0 -1
- package/sdk-core/core-api/src/lib.rs +13 -7
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +21 -5
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +9 -3
- package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
- package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/lib.rs +32 -5
- package/sdk-core/tests/heavy_tests.rs +10 -43
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
- package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
- package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
- package/sdk-core/tests/main.rs +16 -25
- package/sdk-core/tests/runner.rs +11 -9
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
+
internal_flags::CoreInternalFlags,
|
|
2
3
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
3
4
|
test_help::{canned_histories, mock_sdk, mock_sdk_cfg, MockPollCfg, ResponseType},
|
|
4
5
|
worker::client::mocks::mock_workflow_client,
|
|
@@ -8,8 +9,16 @@ use std::{
|
|
|
8
9
|
time::Duration,
|
|
9
10
|
};
|
|
10
11
|
use temporal_client::WorkflowOptions;
|
|
11
|
-
use temporal_sdk::{
|
|
12
|
-
|
|
12
|
+
use temporal_sdk::{
|
|
13
|
+
ActivityOptions, ChildWorkflowOptions, LocalActivityOptions, WfContext, WorkflowResult,
|
|
14
|
+
};
|
|
15
|
+
use temporal_sdk_core_protos::{
|
|
16
|
+
temporal::api::{
|
|
17
|
+
enums::v1::{EventType, WorkflowTaskFailedCause},
|
|
18
|
+
failure::v1::Failure,
|
|
19
|
+
},
|
|
20
|
+
TestHistoryBuilder, DEFAULT_ACTIVITY_TYPE,
|
|
21
|
+
};
|
|
13
22
|
|
|
14
23
|
static DID_FAIL: AtomicBool = AtomicBool::new(false);
|
|
15
24
|
pub async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
|
|
@@ -105,3 +114,204 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
105
114
|
// timer and proceed without restarting
|
|
106
115
|
assert_eq!(2, started_count.load(Ordering::Relaxed));
|
|
107
116
|
}
|
|
117
|
+
|
|
118
|
+
#[rstest::rstest]
|
|
119
|
+
#[tokio::test]
|
|
120
|
+
async fn activity_id_or_type_change_is_nondeterministic(
|
|
121
|
+
#[values(true, false)] use_cache: bool,
|
|
122
|
+
#[values(true, false)] id_change: bool,
|
|
123
|
+
#[values(true, false)] local_act: bool,
|
|
124
|
+
) {
|
|
125
|
+
let wf_id = "fakeid";
|
|
126
|
+
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
127
|
+
let mut t = if local_act {
|
|
128
|
+
canned_histories::single_local_activity("1")
|
|
129
|
+
} else {
|
|
130
|
+
canned_histories::single_activity("1")
|
|
131
|
+
};
|
|
132
|
+
t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
|
|
133
|
+
let mock = mock_workflow_client();
|
|
134
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
135
|
+
wf_id,
|
|
136
|
+
t,
|
|
137
|
+
// Two polls are needed, since the first will fail
|
|
138
|
+
[ResponseType::AllHistory, ResponseType::AllHistory],
|
|
139
|
+
mock,
|
|
140
|
+
);
|
|
141
|
+
// We should see one wft failure which has nondeterminism cause
|
|
142
|
+
mh.num_expected_fails = 1;
|
|
143
|
+
mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
|
|
144
|
+
let should_contain = if id_change {
|
|
145
|
+
"does not match activity id"
|
|
146
|
+
} else {
|
|
147
|
+
"does not match activity type"
|
|
148
|
+
};
|
|
149
|
+
matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
|
|
150
|
+
&& matches!(f, Some(Failure {
|
|
151
|
+
message,
|
|
152
|
+
..
|
|
153
|
+
}) if message.contains(should_contain))
|
|
154
|
+
});
|
|
155
|
+
let mut worker = mock_sdk_cfg(mh, |cfg| {
|
|
156
|
+
if use_cache {
|
|
157
|
+
cfg.max_cached_workflows = 2;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
|
|
162
|
+
if local_act {
|
|
163
|
+
ctx.local_activity(if id_change {
|
|
164
|
+
LocalActivityOptions {
|
|
165
|
+
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
166
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
167
|
+
..Default::default()
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
LocalActivityOptions {
|
|
171
|
+
activity_type: "not the default act type".to_string(),
|
|
172
|
+
..Default::default()
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
.await;
|
|
176
|
+
} else {
|
|
177
|
+
ctx.activity(if id_change {
|
|
178
|
+
ActivityOptions {
|
|
179
|
+
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
180
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
181
|
+
..Default::default()
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
ActivityOptions {
|
|
185
|
+
activity_type: "not the default act type".to_string(),
|
|
186
|
+
..Default::default()
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
.await;
|
|
190
|
+
}
|
|
191
|
+
Ok(().into())
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
worker
|
|
195
|
+
.submit_wf(
|
|
196
|
+
wf_id.to_owned(),
|
|
197
|
+
wf_type.to_owned(),
|
|
198
|
+
vec![],
|
|
199
|
+
WorkflowOptions::default(),
|
|
200
|
+
)
|
|
201
|
+
.await
|
|
202
|
+
.unwrap();
|
|
203
|
+
worker.run_until_done().await.unwrap();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
#[rstest::rstest]
|
|
207
|
+
#[tokio::test]
|
|
208
|
+
async fn child_wf_id_or_type_change_is_nondeterministic(
|
|
209
|
+
#[values(true, false)] use_cache: bool,
|
|
210
|
+
#[values(true, false)] id_change: bool,
|
|
211
|
+
) {
|
|
212
|
+
let wf_id = "fakeid";
|
|
213
|
+
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
214
|
+
let mut t = canned_histories::single_child_workflow("1");
|
|
215
|
+
t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
|
|
216
|
+
let mock = mock_workflow_client();
|
|
217
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
218
|
+
wf_id,
|
|
219
|
+
t,
|
|
220
|
+
// Two polls are needed, since the first will fail
|
|
221
|
+
[ResponseType::AllHistory, ResponseType::AllHistory],
|
|
222
|
+
mock,
|
|
223
|
+
);
|
|
224
|
+
// We should see one wft failure which has nondeterminism cause
|
|
225
|
+
mh.num_expected_fails = 1;
|
|
226
|
+
mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
|
|
227
|
+
let should_contain = if id_change {
|
|
228
|
+
"does not match child workflow id"
|
|
229
|
+
} else {
|
|
230
|
+
"does not match child workflow type"
|
|
231
|
+
};
|
|
232
|
+
matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
|
|
233
|
+
&& matches!(f, Some(Failure {
|
|
234
|
+
message,
|
|
235
|
+
..
|
|
236
|
+
}) if message.contains(should_contain))
|
|
237
|
+
});
|
|
238
|
+
let mut worker = mock_sdk_cfg(mh, |cfg| {
|
|
239
|
+
if use_cache {
|
|
240
|
+
cfg.max_cached_workflows = 2;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
|
|
245
|
+
ctx.child_workflow(if id_change {
|
|
246
|
+
ChildWorkflowOptions {
|
|
247
|
+
workflow_id: "I'm bad and wrong!".to_string(),
|
|
248
|
+
workflow_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
249
|
+
..Default::default()
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
ChildWorkflowOptions {
|
|
253
|
+
workflow_id: "1".to_string(),
|
|
254
|
+
workflow_type: "not the child wf type".to_string(),
|
|
255
|
+
..Default::default()
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
.start(&ctx)
|
|
259
|
+
.await;
|
|
260
|
+
Ok(().into())
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
worker
|
|
264
|
+
.submit_wf(
|
|
265
|
+
wf_id.to_owned(),
|
|
266
|
+
wf_type.to_owned(),
|
|
267
|
+
vec![],
|
|
268
|
+
WorkflowOptions::default(),
|
|
269
|
+
)
|
|
270
|
+
.await
|
|
271
|
+
.unwrap();
|
|
272
|
+
worker.run_until_done().await.unwrap();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/// Repros a situation where if, upon completing a task there is some internal error which causes
|
|
276
|
+
/// us to want to auto-fail the workflow task while there is also an outstanding eviction, the wf
|
|
277
|
+
/// would get evicted but then try to send some info down the completion channel afterward, causing
|
|
278
|
+
/// a panic.
|
|
279
|
+
#[tokio::test]
|
|
280
|
+
async fn repro_channel_missing_because_nondeterminism() {
|
|
281
|
+
for _ in 1..50 {
|
|
282
|
+
let wf_id = "fakeid";
|
|
283
|
+
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
284
|
+
let mut t = TestHistoryBuilder::default();
|
|
285
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
286
|
+
t.add_full_wf_task();
|
|
287
|
+
t.add_has_change_marker("patch-1", false);
|
|
288
|
+
let _ts = t.add_by_type(EventType::TimerStarted);
|
|
289
|
+
t.add_workflow_task_scheduled_and_started();
|
|
290
|
+
|
|
291
|
+
let mock = mock_workflow_client();
|
|
292
|
+
let mut mh =
|
|
293
|
+
MockPollCfg::from_resp_batches(wf_id, t, [1.into(), ResponseType::AllHistory], mock);
|
|
294
|
+
mh.num_expected_fails = 1;
|
|
295
|
+
let mut worker = mock_sdk_cfg(mh, |cfg| {
|
|
296
|
+
cfg.max_cached_workflows = 2;
|
|
297
|
+
cfg.ignore_evicts_on_shutdown = false;
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
|
|
301
|
+
ctx.patched("wrongid");
|
|
302
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
303
|
+
Ok(().into())
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
worker
|
|
307
|
+
.submit_wf(
|
|
308
|
+
wf_id.to_owned(),
|
|
309
|
+
wf_type.to_owned(),
|
|
310
|
+
vec![],
|
|
311
|
+
WorkflowOptions::default(),
|
|
312
|
+
)
|
|
313
|
+
.await
|
|
314
|
+
.unwrap();
|
|
315
|
+
worker.run_until_done().await.unwrap();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -8,6 +8,7 @@ use crate::{
|
|
|
8
8
|
worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
|
|
9
9
|
};
|
|
10
10
|
use anyhow::anyhow;
|
|
11
|
+
use crossbeam::queue::SegQueue;
|
|
11
12
|
use futures::{future::join_all, FutureExt};
|
|
12
13
|
use std::{
|
|
13
14
|
collections::HashMap,
|
|
@@ -22,26 +23,32 @@ use temporal_client::WorkflowOptions;
|
|
|
22
23
|
use temporal_sdk::{
|
|
23
24
|
ActContext, ActivityCancelledError, LocalActivityOptions, WfContext, WorkflowResult,
|
|
24
25
|
};
|
|
25
|
-
use temporal_sdk_core_api::
|
|
26
|
+
use temporal_sdk_core_api::{
|
|
27
|
+
errors::{PollActivityError, PollWfError},
|
|
28
|
+
Worker,
|
|
29
|
+
};
|
|
26
30
|
use temporal_sdk_core_protos::{
|
|
27
31
|
coresdk::{
|
|
28
32
|
activity_result::ActivityExecutionResult,
|
|
29
33
|
workflow_activation::{workflow_activation_job, WorkflowActivationJob},
|
|
30
|
-
workflow_commands::{
|
|
34
|
+
workflow_commands::{
|
|
35
|
+
ActivityCancellationType, QueryResult, QuerySuccess, ScheduleLocalActivity,
|
|
36
|
+
},
|
|
31
37
|
workflow_completion::WorkflowActivationCompletion,
|
|
32
38
|
ActivityTaskCompletion, AsJsonPayloadExt,
|
|
33
39
|
},
|
|
34
40
|
temporal::api::{
|
|
35
41
|
common::v1::RetryPolicy,
|
|
36
42
|
enums::v1::{EventType, TimeoutType, WorkflowTaskFailedCause},
|
|
37
|
-
failure::v1::Failure,
|
|
43
|
+
failure::v1::{failure::FailureInfo, Failure},
|
|
38
44
|
query::v1::WorkflowQuery,
|
|
39
45
|
},
|
|
46
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
40
47
|
};
|
|
41
48
|
use temporal_sdk_core_test_utils::{
|
|
42
49
|
schedule_local_activity_cmd, start_timer_cmd, WorkerTestHelpers,
|
|
43
50
|
};
|
|
44
|
-
use tokio::sync::Barrier;
|
|
51
|
+
use tokio::{join, sync::Barrier};
|
|
45
52
|
|
|
46
53
|
async fn echo(_ctx: ActContext, e: String) -> anyhow::Result<String> {
|
|
47
54
|
Ok(e)
|
|
@@ -59,7 +66,7 @@ async fn local_act_two_wfts_before_marker(#[case] replay: bool, #[case] cached:
|
|
|
59
66
|
let mut t = TestHistoryBuilder::default();
|
|
60
67
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
61
68
|
t.add_full_wf_task();
|
|
62
|
-
let timer_started_event_id = t.
|
|
69
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
63
70
|
t.add_full_wf_task();
|
|
64
71
|
t.add_local_activity_result_marker(1, "1", b"echo".into());
|
|
65
72
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
@@ -84,7 +91,7 @@ async fn local_act_two_wfts_before_marker(#[case] replay: bool, #[case] cached:
|
|
|
84
91
|
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
85
92
|
|ctx: WfContext| async move {
|
|
86
93
|
let la = ctx.local_activity(LocalActivityOptions {
|
|
87
|
-
activity_type:
|
|
94
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
88
95
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
89
96
|
..Default::default()
|
|
90
97
|
});
|
|
@@ -93,7 +100,7 @@ async fn local_act_two_wfts_before_marker(#[case] replay: bool, #[case] cached:
|
|
|
93
100
|
Ok(().into())
|
|
94
101
|
},
|
|
95
102
|
);
|
|
96
|
-
worker.register_activity(
|
|
103
|
+
worker.register_activity(DEFAULT_ACTIVITY_TYPE, echo);
|
|
97
104
|
worker
|
|
98
105
|
.submit_wf(
|
|
99
106
|
wf_id.to_owned(),
|
|
@@ -125,11 +132,10 @@ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
125
132
|
|
|
126
133
|
#[tokio::test]
|
|
127
134
|
async fn local_act_many_concurrent() {
|
|
128
|
-
crate::telemetry::test_telem_console();
|
|
129
135
|
let mut t = TestHistoryBuilder::default();
|
|
130
136
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
131
137
|
t.add_full_wf_task();
|
|
132
|
-
let timer_started_event_id = t.
|
|
138
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
133
139
|
t.add_full_wf_task();
|
|
134
140
|
for i in 1..=50 {
|
|
135
141
|
t.add_local_activity_result_marker(i, &i.to_string(), b"echo".into());
|
|
@@ -301,7 +307,7 @@ async fn local_act_retry_long_backoff_uses_timer() {
|
|
|
301
307
|
"1",
|
|
302
308
|
Failure::application_failure("la failed".to_string(), false),
|
|
303
309
|
);
|
|
304
|
-
let timer_started_event_id = t.
|
|
310
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
305
311
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
306
312
|
t.add_full_wf_task();
|
|
307
313
|
t.add_local_activity_fail_marker(
|
|
@@ -309,7 +315,7 @@ async fn local_act_retry_long_backoff_uses_timer() {
|
|
|
309
315
|
"2",
|
|
310
316
|
Failure::application_failure("la failed".to_string(), false),
|
|
311
317
|
);
|
|
312
|
-
let timer_started_event_id = t.
|
|
318
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
313
319
|
t.add_timer_fired(timer_started_event_id, "2".to_string());
|
|
314
320
|
t.add_full_wf_task();
|
|
315
321
|
t.add_workflow_execution_completed();
|
|
@@ -329,7 +335,7 @@ async fn local_act_retry_long_backoff_uses_timer() {
|
|
|
329
335
|
|ctx: WfContext| async move {
|
|
330
336
|
let la_res = ctx
|
|
331
337
|
.local_activity(LocalActivityOptions {
|
|
332
|
-
activity_type:
|
|
338
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
333
339
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
334
340
|
retry_policy: RetryPolicy {
|
|
335
341
|
initial_interval: Some(prost_dur!(from_millis(65))),
|
|
@@ -348,9 +354,12 @@ async fn local_act_retry_long_backoff_uses_timer() {
|
|
|
348
354
|
Ok(().into())
|
|
349
355
|
},
|
|
350
356
|
);
|
|
351
|
-
worker.register_activity(
|
|
352
|
-
|
|
353
|
-
|
|
357
|
+
worker.register_activity(
|
|
358
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
359
|
+
move |_ctx: ActContext, _: String| async move {
|
|
360
|
+
Result::<(), _>::Err(anyhow!("Oh no I failed!"))
|
|
361
|
+
},
|
|
362
|
+
);
|
|
354
363
|
worker
|
|
355
364
|
.submit_wf(
|
|
356
365
|
wf_id.to_owned(),
|
|
@@ -410,7 +419,7 @@ async fn local_act_command_immediately_follows_la_marker() {
|
|
|
410
419
|
t.add_full_wf_task();
|
|
411
420
|
t.add_full_wf_task();
|
|
412
421
|
t.add_local_activity_result_marker(1, "1", "done".into());
|
|
413
|
-
t.
|
|
422
|
+
t.add_by_type(EventType::TimerStarted);
|
|
414
423
|
t.add_full_wf_task();
|
|
415
424
|
|
|
416
425
|
let wf_id = "fakeid";
|
|
@@ -498,7 +507,7 @@ async fn query_during_wft_heartbeat_doesnt_accidentally_fail_to_continue_heartbe
|
|
|
498
507
|
task.run_id,
|
|
499
508
|
schedule_local_activity_cmd(
|
|
500
509
|
1,
|
|
501
|
-
"
|
|
510
|
+
"1",
|
|
502
511
|
ActivityCancellationType::TryCancel,
|
|
503
512
|
Duration::from_secs(60),
|
|
504
513
|
),
|
|
@@ -564,15 +573,11 @@ async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_quer
|
|
|
564
573
|
// never happen, but there was an issue where an LA resolving could trigger that.
|
|
565
574
|
let wfid = "fake_wf_id";
|
|
566
575
|
let mut t = TestHistoryBuilder::default();
|
|
567
|
-
|
|
568
|
-
t.add(
|
|
569
|
-
EventType::WorkflowExecutionStarted,
|
|
570
|
-
wes_short_wft_timeout.into(),
|
|
571
|
-
);
|
|
576
|
+
t.add(default_wes_attribs());
|
|
572
577
|
// Since we don't send queries with start workflow, need one workflow task of something else
|
|
573
578
|
// b/c we want to get an activation with a job and a nonlegacy query
|
|
574
579
|
t.add_full_wf_task();
|
|
575
|
-
let timer_started_event_id = t.
|
|
580
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
576
581
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
577
582
|
|
|
578
583
|
// nonlegacy query got here & LA started here
|
|
@@ -760,6 +765,15 @@ async fn test_schedule_to_start_timeout() {
|
|
|
760
765
|
})
|
|
761
766
|
.await;
|
|
762
767
|
assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToStart));
|
|
768
|
+
let rfail = la_res.unwrap_failure();
|
|
769
|
+
assert_matches!(
|
|
770
|
+
rfail.failure_info,
|
|
771
|
+
Some(FailureInfo::ActivityFailureInfo(_))
|
|
772
|
+
);
|
|
773
|
+
assert_matches!(
|
|
774
|
+
rfail.cause.unwrap().failure_info,
|
|
775
|
+
Some(FailureInfo::TimeoutFailureInfo(_))
|
|
776
|
+
);
|
|
763
777
|
Ok(().into())
|
|
764
778
|
},
|
|
765
779
|
);
|
|
@@ -808,7 +822,7 @@ async fn test_schedule_to_start_timeout_not_based_on_original_time(
|
|
|
808
822
|
deets.backoff = Some(prost_dur!(from_secs(100)));
|
|
809
823
|
},
|
|
810
824
|
);
|
|
811
|
-
let timer_started_event_id = t.
|
|
825
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
812
826
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
813
827
|
t.add_workflow_task_scheduled_and_started();
|
|
814
828
|
|
|
@@ -874,7 +888,7 @@ async fn wft_failure_cancels_running_las() {
|
|
|
874
888
|
let mut t = TestHistoryBuilder::default();
|
|
875
889
|
t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
|
|
876
890
|
t.add_full_wf_task();
|
|
877
|
-
let timer_started_event_id = t.
|
|
891
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
878
892
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
879
893
|
t.add_workflow_task_scheduled_and_started();
|
|
880
894
|
|
|
@@ -888,7 +902,7 @@ async fn wft_failure_cancels_running_las() {
|
|
|
888
902
|
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
889
903
|
|ctx: WfContext| async move {
|
|
890
904
|
let la_handle = ctx.local_activity(LocalActivityOptions {
|
|
891
|
-
activity_type:
|
|
905
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
892
906
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
893
907
|
..Default::default()
|
|
894
908
|
});
|
|
@@ -902,13 +916,16 @@ async fn wft_failure_cancels_running_las() {
|
|
|
902
916
|
Ok(().into())
|
|
903
917
|
},
|
|
904
918
|
);
|
|
905
|
-
worker.register_activity(
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
919
|
+
worker.register_activity(
|
|
920
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
921
|
+
move |ctx: ActContext, _: String| async move {
|
|
922
|
+
let res = tokio::time::timeout(Duration::from_millis(500), ctx.cancelled()).await;
|
|
923
|
+
if res.is_err() {
|
|
924
|
+
panic!("Activity must be cancelled!!!!");
|
|
925
|
+
}
|
|
926
|
+
Result::<(), _>::Err(ActivityCancelledError::default().into())
|
|
927
|
+
},
|
|
928
|
+
);
|
|
912
929
|
worker
|
|
913
930
|
.submit_wf(
|
|
914
931
|
wf_id.to_owned(),
|
|
@@ -944,9 +961,7 @@ async fn resolved_las_not_recorded_if_wft_fails_many_times() {
|
|
|
944
961
|
mock,
|
|
945
962
|
);
|
|
946
963
|
mh.num_expected_fails = 2;
|
|
947
|
-
mh.
|
|
948
|
-
panic!("should never successfully complete a WFT");
|
|
949
|
-
}));
|
|
964
|
+
mh.num_expected_completions = Some(0.into());
|
|
950
965
|
let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
|
|
951
966
|
|
|
952
967
|
worker.register_wf(
|
|
@@ -976,3 +991,135 @@ async fn resolved_las_not_recorded_if_wft_fails_many_times() {
|
|
|
976
991
|
.unwrap();
|
|
977
992
|
worker.run_until_done().await.unwrap();
|
|
978
993
|
}
|
|
994
|
+
|
|
995
|
+
#[tokio::test]
|
|
996
|
+
async fn local_act_records_nonfirst_attempts_ok() {
|
|
997
|
+
let mut t = TestHistoryBuilder::default();
|
|
998
|
+
let wft_timeout = Duration::from_millis(200);
|
|
999
|
+
t.add_wfe_started_with_wft_timeout(wft_timeout);
|
|
1000
|
+
t.add_full_wf_task();
|
|
1001
|
+
t.add_full_wf_task();
|
|
1002
|
+
t.add_full_wf_task();
|
|
1003
|
+
t.add_workflow_task_scheduled_and_started();
|
|
1004
|
+
|
|
1005
|
+
let wf_id = "fakeid";
|
|
1006
|
+
let mock = mock_workflow_client();
|
|
1007
|
+
let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 3], mock);
|
|
1008
|
+
let nonfirst_counts = Arc::new(SegQueue::new());
|
|
1009
|
+
let nfc_c = nonfirst_counts.clone();
|
|
1010
|
+
mh.completion_asserts = Some(Box::new(move |c| {
|
|
1011
|
+
nfc_c.push(
|
|
1012
|
+
c.metering_metadata
|
|
1013
|
+
.nonfirst_local_activity_execution_attempts,
|
|
1014
|
+
);
|
|
1015
|
+
}));
|
|
1016
|
+
let mut worker = mock_sdk_cfg(mh, |wc| {
|
|
1017
|
+
wc.max_cached_workflows = 1;
|
|
1018
|
+
wc.max_outstanding_workflow_tasks = 1;
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
worker.register_wf(
|
|
1022
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
1023
|
+
|ctx: WfContext| async move {
|
|
1024
|
+
ctx.local_activity(LocalActivityOptions {
|
|
1025
|
+
activity_type: "echo".to_string(),
|
|
1026
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
1027
|
+
retry_policy: RetryPolicy {
|
|
1028
|
+
initial_interval: Some(prost_dur!(from_millis(10))),
|
|
1029
|
+
backoff_coefficient: 1.0,
|
|
1030
|
+
maximum_interval: None,
|
|
1031
|
+
maximum_attempts: 0,
|
|
1032
|
+
non_retryable_error_types: vec![],
|
|
1033
|
+
},
|
|
1034
|
+
..Default::default()
|
|
1035
|
+
})
|
|
1036
|
+
.await;
|
|
1037
|
+
Ok(().into())
|
|
1038
|
+
},
|
|
1039
|
+
);
|
|
1040
|
+
worker.register_activity("echo", move |_ctx: ActContext, _: String| async move {
|
|
1041
|
+
Result::<(), _>::Err(anyhow!("I fail"))
|
|
1042
|
+
});
|
|
1043
|
+
worker
|
|
1044
|
+
.submit_wf(
|
|
1045
|
+
wf_id.to_owned(),
|
|
1046
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
1047
|
+
vec![],
|
|
1048
|
+
WorkflowOptions::default(),
|
|
1049
|
+
)
|
|
1050
|
+
.await
|
|
1051
|
+
.unwrap();
|
|
1052
|
+
worker.run_until_done().await.unwrap();
|
|
1053
|
+
// 3 workflow tasks
|
|
1054
|
+
assert_eq!(nonfirst_counts.len(), 3);
|
|
1055
|
+
// First task's non-first count should, of course, be 0
|
|
1056
|
+
assert_eq!(nonfirst_counts.pop().unwrap(), 0);
|
|
1057
|
+
// Next two, some nonzero amount which could vary based on test load
|
|
1058
|
+
assert!(nonfirst_counts.pop().unwrap() > 0);
|
|
1059
|
+
assert!(nonfirst_counts.pop().unwrap() > 0);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
#[tokio::test]
|
|
1063
|
+
async fn local_activities_can_be_delivered_during_shutdown() {
|
|
1064
|
+
let wfid = "fake_wf_id";
|
|
1065
|
+
let mut t = TestHistoryBuilder::default();
|
|
1066
|
+
t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
|
|
1067
|
+
t.add_full_wf_task();
|
|
1068
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
1069
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
1070
|
+
t.add_workflow_task_scheduled_and_started();
|
|
1071
|
+
|
|
1072
|
+
let mock = mock_workflow_client();
|
|
1073
|
+
let mut mock = single_hist_mock_sg(
|
|
1074
|
+
wfid,
|
|
1075
|
+
t,
|
|
1076
|
+
[ResponseType::ToTaskNum(1), ResponseType::AllHistory],
|
|
1077
|
+
mock,
|
|
1078
|
+
true,
|
|
1079
|
+
);
|
|
1080
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
1081
|
+
let core = mock_worker(mock);
|
|
1082
|
+
|
|
1083
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
1084
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
1085
|
+
task.run_id,
|
|
1086
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
1087
|
+
))
|
|
1088
|
+
.await
|
|
1089
|
+
.unwrap();
|
|
1090
|
+
|
|
1091
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
1092
|
+
// Initiate shutdown once we have the WF activation, but before replying that we want to do an
|
|
1093
|
+
// LA
|
|
1094
|
+
core.initiate_shutdown();
|
|
1095
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
1096
|
+
task.run_id,
|
|
1097
|
+
ScheduleLocalActivity {
|
|
1098
|
+
seq: 1,
|
|
1099
|
+
activity_id: "1".to_string(),
|
|
1100
|
+
activity_type: "test_act".to_string(),
|
|
1101
|
+
start_to_close_timeout: Some(prost_dur!(from_secs(30))),
|
|
1102
|
+
..Default::default()
|
|
1103
|
+
}
|
|
1104
|
+
.into(),
|
|
1105
|
+
))
|
|
1106
|
+
.await
|
|
1107
|
+
.unwrap();
|
|
1108
|
+
|
|
1109
|
+
let wf_poller = async { core.poll_workflow_activation().await };
|
|
1110
|
+
|
|
1111
|
+
let at_poller = async {
|
|
1112
|
+
let act_task = core.poll_activity_task().await.unwrap();
|
|
1113
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
1114
|
+
task_token: act_task.task_token,
|
|
1115
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
1116
|
+
})
|
|
1117
|
+
.await
|
|
1118
|
+
.unwrap();
|
|
1119
|
+
core.poll_activity_task().await
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
let (wf_r, act_r) = join!(wf_poller, at_poller);
|
|
1123
|
+
assert_matches!(wf_r.unwrap_err(), PollWfError::ShutDown);
|
|
1124
|
+
assert_matches!(act_r.unwrap_err(), PollActivityError::ShutDown);
|
|
1125
|
+
}
|
|
@@ -23,7 +23,7 @@ use temporal_sdk_core_protos::{
|
|
|
23
23
|
},
|
|
24
24
|
temporal::api::{
|
|
25
25
|
common::v1::Payload,
|
|
26
|
-
enums::v1::EventType,
|
|
26
|
+
enums::v1::{CommandType, EventType},
|
|
27
27
|
failure::v1::Failure,
|
|
28
28
|
history::v1::{history_event, ActivityTaskCancelRequestedEventAttributes, History},
|
|
29
29
|
query::v1::WorkflowQuery,
|
|
@@ -148,10 +148,11 @@ async fn legacy_query(#[case] include_history: bool) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
#[rstest::rstest]
|
|
151
|
-
#[case::one_query(1)]
|
|
152
|
-
#[case::multiple_queries(3)]
|
|
153
151
|
#[tokio::test]
|
|
154
|
-
async fn new_queries(
|
|
152
|
+
async fn new_queries(
|
|
153
|
+
#[values(1, 3)] num_queries: usize,
|
|
154
|
+
#[values(false, true)] query_results_after_complete: bool,
|
|
155
|
+
) {
|
|
155
156
|
let wfid = "fake_wf_id";
|
|
156
157
|
let query_resp = "response";
|
|
157
158
|
let t = canned_histories::single_timer("1");
|
|
@@ -174,7 +175,18 @@ async fn new_queries(#[case] num_queries: usize) {
|
|
|
174
175
|
}]);
|
|
175
176
|
let mut mock_client = mock_workflow_client();
|
|
176
177
|
mock_client.expect_respond_legacy_query().times(0);
|
|
177
|
-
let mut
|
|
178
|
+
let mut mh = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
|
|
179
|
+
mh.completion_asserts = Some(Box::new(move |c| {
|
|
180
|
+
// If the completion is the one ending the workflow, make sure it includes the query resps
|
|
181
|
+
if c.commands[0].command_type() == CommandType::CompleteWorkflowExecution {
|
|
182
|
+
assert_eq!(c.query_responses.len(), num_queries);
|
|
183
|
+
} else if c.commands[0].command_type() == CommandType::StartTimer {
|
|
184
|
+
// first reply, no queries here.
|
|
185
|
+
} else {
|
|
186
|
+
panic!("Unexpected command in response")
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
let mut mock = build_mock_pollers(mh);
|
|
178
190
|
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
179
191
|
let core = mock_worker(mock);
|
|
180
192
|
|
|
@@ -203,8 +215,13 @@ async fn new_queries(#[case] num_queries: usize) {
|
|
|
203
215
|
}
|
|
204
216
|
);
|
|
205
217
|
}
|
|
206
|
-
|
|
207
|
-
|
|
218
|
+
|
|
219
|
+
let mut commands = vec![];
|
|
220
|
+
if query_results_after_complete {
|
|
221
|
+
commands.push(CompleteWorkflowExecution { result: None }.into());
|
|
222
|
+
}
|
|
223
|
+
for i in 1..=num_queries {
|
|
224
|
+
commands.push(
|
|
208
225
|
QueryResult {
|
|
209
226
|
query_id: format!("q{i}"),
|
|
210
227
|
variant: Some(
|
|
@@ -214,13 +231,15 @@ async fn new_queries(#[case] num_queries: usize) {
|
|
|
214
231
|
.into(),
|
|
215
232
|
),
|
|
216
233
|
}
|
|
217
|
-
.into()
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
234
|
+
.into(),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
if !query_results_after_complete {
|
|
238
|
+
commands.push(CompleteWorkflowExecution { result: None }.into());
|
|
239
|
+
}
|
|
221
240
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
222
241
|
task.run_id,
|
|
223
|
-
|
|
242
|
+
commands,
|
|
224
243
|
))
|
|
225
244
|
.await
|
|
226
245
|
.unwrap();
|
|
@@ -769,11 +788,10 @@ async fn legacy_query_combined_with_timer_fire_repro() {
|
|
|
769
788
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
770
789
|
t.add_full_wf_task();
|
|
771
790
|
let scheduled_event_id = t.add_activity_task_scheduled("1");
|
|
772
|
-
let timer_started_event_id = t.
|
|
791
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
773
792
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
774
793
|
t.add_full_wf_task();
|
|
775
794
|
t.add(
|
|
776
|
-
EventType::ActivityTaskCancelRequested,
|
|
777
795
|
history_event::Attributes::ActivityTaskCancelRequestedEventAttributes(
|
|
778
796
|
ActivityTaskCancelRequestedEventAttributes {
|
|
779
797
|
scheduled_event_id,
|