@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
|
@@ -15,7 +15,7 @@ use crate::{
|
|
|
15
15
|
worker::{LocalActRequest, LocalActivityResolution},
|
|
16
16
|
};
|
|
17
17
|
use machines::WorkflowMachines;
|
|
18
|
-
use std::{result, sync::mpsc::Sender};
|
|
18
|
+
use std::{result, sync::mpsc::Sender, time::Duration};
|
|
19
19
|
use temporal_sdk_core_protos::{
|
|
20
20
|
coresdk::{workflow_activation::WorkflowActivation, workflow_commands::*},
|
|
21
21
|
temporal::api::command::v1::Command as ProtoCommand,
|
|
@@ -213,6 +213,7 @@ pub enum WFCommand {
|
|
|
213
213
|
RequestCancelExternalWorkflow(RequestCancelExternalWorkflowExecution),
|
|
214
214
|
SignalExternalWorkflow(SignalExternalWorkflowExecution),
|
|
215
215
|
CancelSignalWorkflow(CancelSignalWorkflow),
|
|
216
|
+
UpsertSearchAttributes(UpsertWorkflowSearchAttributes),
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
impl TryFrom<WorkflowCommand> for WFCommand {
|
|
@@ -253,6 +254,9 @@ impl TryFrom<WorkflowCommand> for WFCommand {
|
|
|
253
254
|
workflow_command::Variant::RequestCancelLocalActivity(s) => {
|
|
254
255
|
Ok(Self::RequestCancelLocalActivity(s))
|
|
255
256
|
}
|
|
257
|
+
workflow_command::Variant::UpsertWorkflowSearchAttributesCommandAttributes(s) => {
|
|
258
|
+
Ok(Self::UpsertSearchAttributes(s))
|
|
259
|
+
}
|
|
256
260
|
}
|
|
257
261
|
}
|
|
258
262
|
}
|
|
@@ -267,6 +271,14 @@ enum CommandID {
|
|
|
267
271
|
CancelExternal(u32),
|
|
268
272
|
}
|
|
269
273
|
|
|
274
|
+
/// Details remembered from the workflow execution started event that we may need to recall later.
|
|
275
|
+
/// Is a subset of `WorkflowExecutionStartedEventAttributes`, but avoids holding on to huge fields.
|
|
276
|
+
#[derive(Debug, Clone)]
|
|
277
|
+
pub struct WorkflowStartedInfo {
|
|
278
|
+
workflow_task_timeout: Option<Duration>,
|
|
279
|
+
workflow_execution_timeout: Option<Duration>,
|
|
280
|
+
}
|
|
281
|
+
|
|
270
282
|
#[cfg(test)]
|
|
271
283
|
pub mod managed_wf {
|
|
272
284
|
use super::*;
|
|
@@ -12,6 +12,7 @@ use std::{
|
|
|
12
12
|
collections::HashMap,
|
|
13
13
|
fmt::Debug,
|
|
14
14
|
ops::{Deref, DerefMut},
|
|
15
|
+
sync::Arc,
|
|
15
16
|
};
|
|
16
17
|
use temporal_sdk_core_protos::coresdk::workflow_activation::WorkflowActivation;
|
|
17
18
|
|
|
@@ -22,7 +23,7 @@ pub(crate) struct WorkflowConcurrencyManager {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
struct ManagedRun {
|
|
25
|
-
wfm: Mutex<WorkflowManager
|
|
26
|
+
wfm: Arc<Mutex<WorkflowManager>>,
|
|
26
27
|
wft: Option<OutstandingTask>,
|
|
27
28
|
activation: Option<OutstandingActivation>,
|
|
28
29
|
metrics: MetricsContext,
|
|
@@ -36,7 +37,7 @@ struct ManagedRun {
|
|
|
36
37
|
impl ManagedRun {
|
|
37
38
|
fn new(wfm: WorkflowManager, metrics: MetricsContext) -> Self {
|
|
38
39
|
Self {
|
|
39
|
-
wfm: Mutex::new(wfm),
|
|
40
|
+
wfm: Arc::new(Mutex::new(wfm)),
|
|
40
41
|
wft: None,
|
|
41
42
|
activation: None,
|
|
42
43
|
metrics,
|
|
@@ -266,16 +267,19 @@ impl WorkflowConcurrencyManager {
|
|
|
266
267
|
F: for<'a> FnOnce(&'a mut WorkflowManager) -> BoxFuture<Result<Fout>>,
|
|
267
268
|
Fout: Send + Debug,
|
|
268
269
|
{
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
270
|
+
// TODO: Slightly less than ideal. We must avoid holding the read lock on the overall
|
|
271
|
+
// machine map while async-ly mutating the inner machine. So, we clone the inner ArcMutex.
|
|
272
|
+
// We should restructure things to avoid the top-level lock on the map.
|
|
273
|
+
|
|
274
|
+
let wfm = {
|
|
275
|
+
let readlock = self.runs.read();
|
|
276
|
+
let m = readlock
|
|
277
|
+
.get(run_id)
|
|
278
|
+
.ok_or_else(|| WFMachinesError::Fatal("Missing workflow machines".to_string()))?;
|
|
279
|
+
m.wfm.clone()
|
|
280
|
+
};
|
|
278
281
|
|
|
282
|
+
let res = mutator(&mut wfm.lock()).await;
|
|
279
283
|
res
|
|
280
284
|
}
|
|
281
285
|
|
|
@@ -321,6 +325,8 @@ impl WorkflowConcurrencyManager {
|
|
|
321
325
|
#[cfg(test)]
|
|
322
326
|
mod tests {
|
|
323
327
|
use super::*;
|
|
328
|
+
use crate::test_help::canned_histories;
|
|
329
|
+
use tokio::sync::Barrier;
|
|
324
330
|
|
|
325
331
|
// We test mostly error paths here since the happy paths are well covered by the tests of the
|
|
326
332
|
// core sdk itself, and setting up the fake data is onerous here. If we make the concurrency
|
|
@@ -342,4 +348,57 @@ mod tests {
|
|
|
342
348
|
// Should whine that the machines have nothing to do (history empty)
|
|
343
349
|
assert_matches!(res.unwrap_err(), WFMachinesError::Fatal { .. });
|
|
344
350
|
}
|
|
351
|
+
|
|
352
|
+
/// This test makes sure that if we're stuck on an await within the machine mutator we don't
|
|
353
|
+
/// cause a deadlock if a write happens during that. This test will hang without proper
|
|
354
|
+
/// implementation.
|
|
355
|
+
#[tokio::test]
|
|
356
|
+
async fn aba_deadlock_prevented() {
|
|
357
|
+
let run_id = "some_run_id";
|
|
358
|
+
let timer_hist = canned_histories::single_timer("t");
|
|
359
|
+
let access_barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
|
|
360
|
+
let wft = timer_hist.get_history_info(1).unwrap();
|
|
361
|
+
|
|
362
|
+
let mgr = WorkflowConcurrencyManager::new();
|
|
363
|
+
mgr.create_or_update(
|
|
364
|
+
run_id,
|
|
365
|
+
wft.clone().into(),
|
|
366
|
+
"fake_wf_id",
|
|
367
|
+
"fake_namespace",
|
|
368
|
+
"fake_wf_type",
|
|
369
|
+
&Default::default(),
|
|
370
|
+
)
|
|
371
|
+
.await
|
|
372
|
+
.unwrap();
|
|
373
|
+
// Perform access which blocks
|
|
374
|
+
let access_fut = mgr.access(run_id, |_wfm| {
|
|
375
|
+
async {
|
|
376
|
+
// Wait to make sure access has started
|
|
377
|
+
access_barr.wait().await;
|
|
378
|
+
// Wait to make sure write has finished
|
|
379
|
+
access_barr.wait().await;
|
|
380
|
+
Ok(())
|
|
381
|
+
}
|
|
382
|
+
.boxed()
|
|
383
|
+
});
|
|
384
|
+
let write_fut = async {
|
|
385
|
+
// Wait to make sure access has started
|
|
386
|
+
access_barr.wait().await;
|
|
387
|
+
// Now try writing
|
|
388
|
+
mgr.create_or_update(
|
|
389
|
+
"different_run_id",
|
|
390
|
+
wft.clone().into(),
|
|
391
|
+
"fake_wf_id",
|
|
392
|
+
"fake_namespace",
|
|
393
|
+
"fake_wf_type",
|
|
394
|
+
&Default::default(),
|
|
395
|
+
)
|
|
396
|
+
.await
|
|
397
|
+
.unwrap();
|
|
398
|
+
// Indicate write has finished
|
|
399
|
+
access_barr.wait().await;
|
|
400
|
+
};
|
|
401
|
+
let (r1, _) = tokio::join!(access_fut, write_fut);
|
|
402
|
+
r1.unwrap();
|
|
403
|
+
}
|
|
345
404
|
}
|
|
@@ -7,8 +7,9 @@ use crate::{
|
|
|
7
7
|
pending_activations::PendingActivations,
|
|
8
8
|
protosext::{ValidPollWFTQResponse, WorkflowActivationExt},
|
|
9
9
|
telemetry::metrics::MetricsContext,
|
|
10
|
-
worker::{LocalActRequest, LocalActivityResolution},
|
|
10
|
+
worker::{client::WorkerClientBag, LocalActRequest, LocalActivityResolution},
|
|
11
11
|
workflow::{
|
|
12
|
+
history_update::NextPageToken,
|
|
12
13
|
machines::WFMachinesError,
|
|
13
14
|
workflow_tasks::{
|
|
14
15
|
cache_manager::WorkflowCacheManager, concurrency_manager::WorkflowConcurrencyManager,
|
|
@@ -26,15 +27,13 @@ use std::{
|
|
|
26
27
|
sync::Arc,
|
|
27
28
|
time::{Duration, Instant},
|
|
28
29
|
};
|
|
29
|
-
use temporal_client::ServerGatewayApis;
|
|
30
30
|
use temporal_sdk_core_protos::{
|
|
31
31
|
coresdk::{
|
|
32
32
|
workflow_activation::{
|
|
33
|
-
create_query_activation, remove_from_cache::EvictionReason,
|
|
34
|
-
QueryWorkflow, WorkflowActivation,
|
|
33
|
+
create_query_activation, query_to_job, remove_from_cache::EvictionReason,
|
|
34
|
+
workflow_activation_job, QueryWorkflow, WorkflowActivation,
|
|
35
35
|
},
|
|
36
36
|
workflow_commands::QueryResult,
|
|
37
|
-
FromPayloadsExt,
|
|
38
37
|
},
|
|
39
38
|
temporal::api::command::v1::Command as ProtoCommand,
|
|
40
39
|
TaskToken,
|
|
@@ -120,8 +119,6 @@ pub(crate) enum NewWfTaskOutcome {
|
|
|
120
119
|
/// The workflow task should be auto-completed with an empty command list, as it must be replied
|
|
121
120
|
/// to but there is no meaningful work for lang to do.
|
|
122
121
|
Autocomplete,
|
|
123
|
-
/// Workflow task had partial history and workflow was not present in the cache.
|
|
124
|
-
CacheMiss,
|
|
125
122
|
/// The workflow task ran into problems while being applied and we must now evict the workflow
|
|
126
123
|
Evict(WorkflowUpdateError),
|
|
127
124
|
/// No action should be taken. Possibly we are waiting for local activities to complete
|
|
@@ -153,6 +150,13 @@ pub(crate) enum ActivationAction {
|
|
|
153
150
|
RespondLegacyQuery { result: QueryResult },
|
|
154
151
|
}
|
|
155
152
|
|
|
153
|
+
#[derive(Debug, Eq, PartialEq, Hash)]
|
|
154
|
+
pub(crate) enum EvictionRequestResult {
|
|
155
|
+
EvictionIssued(Option<u32>),
|
|
156
|
+
NotFound,
|
|
157
|
+
EvictionAlreadyOutstanding,
|
|
158
|
+
}
|
|
159
|
+
|
|
156
160
|
macro_rules! machine_mut {
|
|
157
161
|
($myself:ident, $run_id:ident, $clos:expr) => {{
|
|
158
162
|
$myself
|
|
@@ -250,7 +254,7 @@ impl WorkflowTaskManager {
|
|
|
250
254
|
run_id: &str,
|
|
251
255
|
message: impl Into<String>,
|
|
252
256
|
reason: EvictionReason,
|
|
253
|
-
) ->
|
|
257
|
+
) -> EvictionRequestResult {
|
|
254
258
|
if self.workflow_machines.exists(run_id) {
|
|
255
259
|
if !self.activation_has_eviction(run_id) {
|
|
256
260
|
let message = message.into();
|
|
@@ -259,13 +263,17 @@ impl WorkflowTaskManager {
|
|
|
259
263
|
self.pending_activations
|
|
260
264
|
.notify_needs_eviction(run_id, message, reason);
|
|
261
265
|
self.pending_activations_notifier.notify_waiters();
|
|
266
|
+
EvictionRequestResult::EvictionIssued(
|
|
267
|
+
self.workflow_machines
|
|
268
|
+
.get_task(run_id)
|
|
269
|
+
.map(|wt| wt.info.attempt),
|
|
270
|
+
)
|
|
271
|
+
} else {
|
|
272
|
+
EvictionRequestResult::EvictionAlreadyOutstanding
|
|
262
273
|
}
|
|
263
|
-
self.workflow_machines
|
|
264
|
-
.get_task(run_id)
|
|
265
|
-
.map(|wt| wt.info.attempt)
|
|
266
274
|
} else {
|
|
267
275
|
warn!(%run_id, "Eviction requested for unknown run");
|
|
268
|
-
|
|
276
|
+
EvictionRequestResult::NotFound
|
|
269
277
|
}
|
|
270
278
|
}
|
|
271
279
|
|
|
@@ -298,7 +306,7 @@ impl WorkflowTaskManager {
|
|
|
298
306
|
pub(crate) async fn apply_new_poll_resp(
|
|
299
307
|
&self,
|
|
300
308
|
work: ValidPollWFTQResponse,
|
|
301
|
-
|
|
309
|
+
client: Arc<WorkerClientBag>,
|
|
302
310
|
) -> NewWfTaskOutcome {
|
|
303
311
|
let mut work = if let Some(w) = self.workflow_machines.buffer_resp_if_outstanding_work(work)
|
|
304
312
|
{
|
|
@@ -307,29 +315,28 @@ impl WorkflowTaskManager {
|
|
|
307
315
|
return NewWfTaskOutcome::TaskBuffered;
|
|
308
316
|
};
|
|
309
317
|
|
|
318
|
+
let start_event_id = work.history.events.first().map(|e| e.event_id);
|
|
310
319
|
debug!(
|
|
311
320
|
task_token = %&work.task_token,
|
|
312
321
|
history_length = %work.history.events.len(),
|
|
322
|
+
start_event_id = ?start_event_id,
|
|
313
323
|
attempt = %work.attempt,
|
|
324
|
+
run_id = %work.workflow_execution.run_id,
|
|
314
325
|
"Applying new workflow task from server"
|
|
315
326
|
);
|
|
316
327
|
let task_start_time = Instant::now();
|
|
317
328
|
|
|
318
329
|
// Check if there is a legacy query we either need to immediately issue an activation for
|
|
319
330
|
// (if there is no more replay work to do) or we need to store for later answering.
|
|
320
|
-
let legacy_query = work
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
});
|
|
331
|
+
let legacy_query = work
|
|
332
|
+
.legacy_query
|
|
333
|
+
.take()
|
|
334
|
+
.map(|q| query_to_job(LEGACY_QUERY_ID.to_string(), q));
|
|
325
335
|
|
|
326
336
|
let (info, mut next_activation) =
|
|
327
|
-
match self.instantiate_or_update_workflow(work,
|
|
337
|
+
match self.instantiate_or_update_workflow(work, client).await {
|
|
328
338
|
Ok((info, next_activation)) => (info, next_activation),
|
|
329
339
|
Err(e) => {
|
|
330
|
-
if let WFMachinesError::CacheMiss = e.source {
|
|
331
|
-
return NewWfTaskOutcome::CacheMiss;
|
|
332
|
-
}
|
|
333
340
|
return NewWfTaskOutcome::Evict(e);
|
|
334
341
|
}
|
|
335
342
|
};
|
|
@@ -337,7 +344,7 @@ impl WorkflowTaskManager {
|
|
|
337
344
|
// Immediately dispatch query activation if no other jobs
|
|
338
345
|
let legacy_query = if next_activation.jobs.is_empty() {
|
|
339
346
|
if let Some(lq) = legacy_query {
|
|
340
|
-
debug!("Dispatching legacy query {
|
|
347
|
+
debug!("Dispatching legacy query {}", &lq);
|
|
341
348
|
next_activation
|
|
342
349
|
.jobs
|
|
343
350
|
.push(workflow_activation_job::Variant::QueryWorkflow(lq).into());
|
|
@@ -467,9 +474,8 @@ impl WorkflowTaskManager {
|
|
|
467
474
|
|
|
468
475
|
let wft_timeout: Duration = wfm
|
|
469
476
|
.machines
|
|
470
|
-
.
|
|
471
|
-
.and_then(|attrs| attrs.workflow_task_timeout
|
|
472
|
-
.and_then(|tt| tt.try_into().ok())
|
|
477
|
+
.get_started_info()
|
|
478
|
+
.and_then(|attrs| attrs.workflow_task_timeout)
|
|
473
479
|
.ok_or_else(|| {
|
|
474
480
|
WFMachinesError::Fatal(
|
|
475
481
|
"Workflow's start attribs were missing a well formed task timeout"
|
|
@@ -566,9 +572,10 @@ impl WorkflowTaskManager {
|
|
|
566
572
|
FailedActivationOutcome::ReportLegacyQueryFailure(tt)
|
|
567
573
|
} else {
|
|
568
574
|
// Blow up any cached data associated with the workflow
|
|
569
|
-
let should_report = self
|
|
570
|
-
|
|
571
|
-
|
|
575
|
+
let should_report = match self.request_eviction(run_id, failstr, reason) {
|
|
576
|
+
EvictionRequestResult::EvictionIssued(Some(attempt)) => attempt <= 1,
|
|
577
|
+
_ => false,
|
|
578
|
+
};
|
|
572
579
|
if should_report {
|
|
573
580
|
FailedActivationOutcome::Report(tt)
|
|
574
581
|
} else {
|
|
@@ -584,7 +591,7 @@ impl WorkflowTaskManager {
|
|
|
584
591
|
async fn instantiate_or_update_workflow(
|
|
585
592
|
&self,
|
|
586
593
|
poll_wf_resp: ValidPollWFTQResponse,
|
|
587
|
-
|
|
594
|
+
client: Arc<WorkerClientBag>,
|
|
588
595
|
) -> Result<(WorkflowTaskInfo, WorkflowActivation), WorkflowUpdateError> {
|
|
589
596
|
let run_id = poll_wf_resp.workflow_execution.run_id.clone();
|
|
590
597
|
|
|
@@ -593,22 +600,39 @@ impl WorkflowTaskManager {
|
|
|
593
600
|
task_token: poll_wf_resp.task_token,
|
|
594
601
|
};
|
|
595
602
|
|
|
603
|
+
let poll_resp_is_incremental = poll_wf_resp
|
|
604
|
+
.history
|
|
605
|
+
.events
|
|
606
|
+
.get(0)
|
|
607
|
+
.map(|ev| ev.event_id > 1)
|
|
608
|
+
.unwrap_or_default();
|
|
609
|
+
|
|
610
|
+
let page_token = if !self.workflow_machines.exists(&run_id) && poll_resp_is_incremental {
|
|
611
|
+
debug!(run_id=?run_id, "Workflow task has partial history, but workflow is not in \
|
|
612
|
+
cache. Will fetch history");
|
|
613
|
+
self.metrics.sticky_cache_miss();
|
|
614
|
+
NextPageToken::FetchFromStart
|
|
615
|
+
} else {
|
|
616
|
+
poll_wf_resp.next_page_token.into()
|
|
617
|
+
};
|
|
618
|
+
let history_update = HistoryUpdate::new(
|
|
619
|
+
HistoryPaginator::new(
|
|
620
|
+
poll_wf_resp.history,
|
|
621
|
+
poll_wf_resp.workflow_execution.workflow_id.clone(),
|
|
622
|
+
poll_wf_resp.workflow_execution.run_id,
|
|
623
|
+
page_token,
|
|
624
|
+
client.clone(),
|
|
625
|
+
),
|
|
626
|
+
poll_wf_resp.previous_started_event_id,
|
|
627
|
+
);
|
|
628
|
+
|
|
596
629
|
match self
|
|
597
630
|
.workflow_machines
|
|
598
631
|
.create_or_update(
|
|
599
632
|
&run_id,
|
|
600
|
-
|
|
601
|
-
HistoryPaginator::new(
|
|
602
|
-
poll_wf_resp.history,
|
|
603
|
-
poll_wf_resp.workflow_execution.workflow_id.clone(),
|
|
604
|
-
poll_wf_resp.workflow_execution.run_id.clone(),
|
|
605
|
-
poll_wf_resp.next_page_token,
|
|
606
|
-
gateway.clone(),
|
|
607
|
-
),
|
|
608
|
-
poll_wf_resp.previous_started_event_id,
|
|
609
|
-
),
|
|
633
|
+
history_update,
|
|
610
634
|
&poll_wf_resp.workflow_execution.workflow_id,
|
|
611
|
-
|
|
635
|
+
client.namespace(),
|
|
612
636
|
&poll_wf_resp.workflow_type,
|
|
613
637
|
&self.metrics,
|
|
614
638
|
)
|
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
name = "temporal-sdk-core-api"
|
|
3
3
|
version = "0.1.0"
|
|
4
4
|
edition = "2021"
|
|
5
|
+
authors = ["Spencer Judge <spencer@temporal.io>"]
|
|
6
|
+
license-file = "LICENSE.txt"
|
|
7
|
+
description = "Interface definitions for the Temporal Core SDK"
|
|
8
|
+
homepage = "https://temporal.io/"
|
|
9
|
+
repository = "https://github.com/temporalio/sdk-core"
|
|
10
|
+
keywords = ["temporal", "workflow"]
|
|
11
|
+
categories = ["development-tools"]
|
|
5
12
|
|
|
6
13
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
7
14
|
|
|
8
15
|
[dependencies]
|
|
9
16
|
anyhow = "1.0"
|
|
10
17
|
async-trait = "0.1"
|
|
11
|
-
derive_builder = "0.
|
|
18
|
+
derive_builder = "0.11"
|
|
12
19
|
log = "0.4"
|
|
20
|
+
opentelemetry = "0.17"
|
|
13
21
|
prost-types = "0.9"
|
|
14
22
|
thiserror = "1.0"
|
|
15
23
|
tonic = "0.6"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Temporal Core SDK
|
|
2
|
+
|
|
3
|
+
The MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
//! Error types exposed by public APIs
|
|
2
2
|
|
|
3
3
|
use prost_types::TimestampOutOfSystemRangeError;
|
|
4
|
-
use temporal_client::GatewayInitError;
|
|
5
4
|
use temporal_sdk_core_protos::coresdk::{
|
|
6
5
|
activity_result::ActivityExecutionResult,
|
|
7
6
|
workflow_activation::remove_from_cache::EvictionReason,
|
|
8
7
|
workflow_completion::WorkflowActivationCompletion,
|
|
9
8
|
};
|
|
10
9
|
|
|
11
|
-
/// Errors thrown
|
|
12
|
-
#[derive(thiserror::Error, Debug)]
|
|
13
|
-
pub enum CoreInitError {
|
|
14
|
-
/// Server connection error. Crashing and restarting the worker is likely best.
|
|
15
|
-
#[error("Server connection error: {0:?}")]
|
|
16
|
-
GatewayInitError(#[from] GatewayInitError),
|
|
17
|
-
/// There was a problem initializing telemetry
|
|
18
|
-
#[error("Telemetry initialization error: {0:?}")]
|
|
19
|
-
TelemetryInitError(anyhow::Error),
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/// Errors thrown by [crate::Core::poll_workflow_activation]
|
|
10
|
+
/// Errors thrown by [crate::Worker::poll_workflow_activation]
|
|
23
11
|
#[derive(thiserror::Error, Debug)]
|
|
24
12
|
pub enum PollWfError {
|
|
25
|
-
/// [crate::
|
|
26
|
-
/// must call [crate::
|
|
13
|
+
/// [crate::Worker::shutdown] was called, and there are no more replay tasks to be handled. Lang
|
|
14
|
+
/// must call [crate::Worker::complete_workflow_activation] for any remaining tasks, and then may
|
|
27
15
|
/// exit.
|
|
28
16
|
#[error("Core is shut down and there are no more workflow replay tasks")]
|
|
29
17
|
ShutDown,
|
|
@@ -36,15 +24,12 @@ pub enum PollWfError {
|
|
|
36
24
|
/// even though we already cancelled it)
|
|
37
25
|
#[error("Unhandled error when auto-completing workflow task: {0:?}")]
|
|
38
26
|
AutocompleteError(#[from] CompleteWfError),
|
|
39
|
-
/// There is no worker registered for the queue being polled
|
|
40
|
-
#[error("No worker registered for queue: {0}")]
|
|
41
|
-
NoWorkerForQueue(String),
|
|
42
27
|
}
|
|
43
28
|
|
|
44
|
-
/// Errors thrown by [crate::
|
|
29
|
+
/// Errors thrown by [crate::Worker::poll_activity_task]
|
|
45
30
|
#[derive(thiserror::Error, Debug)]
|
|
46
31
|
pub enum PollActivityError {
|
|
47
|
-
/// [crate::
|
|
32
|
+
/// [crate::Worker::shutdown] was called, we will no longer fetch new activity tasks. Lang must
|
|
48
33
|
/// ensure it is finished with any workflow replay, see [PollWfError::ShutDown]
|
|
49
34
|
#[error("Core is shut down")]
|
|
50
35
|
ShutDown,
|
|
@@ -52,12 +37,9 @@ pub enum PollActivityError {
|
|
|
52
37
|
/// errors, so lang should consider this fatal.
|
|
53
38
|
#[error("Unhandled grpc error when activity polling: {0:?}")]
|
|
54
39
|
TonicError(#[from] tonic::Status),
|
|
55
|
-
/// There is no worker registered for the queue being polled
|
|
56
|
-
#[error("No worker registered for queue: {0}")]
|
|
57
|
-
NoWorkerForQueue(String),
|
|
58
40
|
}
|
|
59
41
|
|
|
60
|
-
/// Errors thrown by [crate::
|
|
42
|
+
/// Errors thrown by [crate::Worker::complete_workflow_activation]
|
|
61
43
|
#[derive(thiserror::Error, Debug)]
|
|
62
44
|
#[allow(clippy::large_enum_variant)]
|
|
63
45
|
pub enum CompleteWfError {
|
|
@@ -78,7 +60,7 @@ pub enum CompleteWfError {
|
|
|
78
60
|
TonicError(#[from] tonic::Status),
|
|
79
61
|
}
|
|
80
62
|
|
|
81
|
-
/// Errors thrown by [crate::
|
|
63
|
+
/// Errors thrown by [crate::Worker::complete_activity_task]
|
|
82
64
|
#[derive(thiserror::Error, Debug)]
|
|
83
65
|
pub enum CompleteActivityError {
|
|
84
66
|
/// Lang SDK sent us a malformed activity completion. This likely means a bug in the lang sdk.
|
|
@@ -98,14 +80,6 @@ pub enum CompleteActivityError {
|
|
|
98
80
|
NoWorkerForQueue(String),
|
|
99
81
|
}
|
|
100
82
|
|
|
101
|
-
/// Errors thrown by [crate::Core::register_worker]
|
|
102
|
-
#[derive(thiserror::Error, Debug)]
|
|
103
|
-
pub enum WorkerRegistrationError {
|
|
104
|
-
/// A worker has already been registered on this queue
|
|
105
|
-
#[error("Worker already registered for queue: {0}")]
|
|
106
|
-
WorkerAlreadyRegisteredForQueue(String),
|
|
107
|
-
}
|
|
108
|
-
|
|
109
83
|
/// Errors thrown inside of workflow machines
|
|
110
84
|
#[derive(thiserror::Error, Debug)]
|
|
111
85
|
pub enum WFMachinesError {
|
|
@@ -116,10 +90,6 @@ pub enum WFMachinesError {
|
|
|
116
90
|
|
|
117
91
|
#[error("Unrecoverable network error while fetching history: {0}")]
|
|
118
92
|
HistoryFetchingError(tonic::Status),
|
|
119
|
-
|
|
120
|
-
/// Should always be caught internally and turned into a workflow task failure
|
|
121
|
-
#[error("Unable to process partial event history because workflow is no longer cached.")]
|
|
122
|
-
CacheMiss,
|
|
123
93
|
}
|
|
124
94
|
|
|
125
95
|
impl WFMachinesError {
|
|
@@ -129,7 +99,6 @@ impl WFMachinesError {
|
|
|
129
99
|
WFMachinesError::Fatal(_) | WFMachinesError::HistoryFetchingError(_) => {
|
|
130
100
|
EvictionReason::Fatal
|
|
131
101
|
}
|
|
132
|
-
WFMachinesError::CacheMiss => EvictionReason::CacheMiss,
|
|
133
102
|
}
|
|
134
103
|
}
|
|
135
104
|
}
|