@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.
Files changed (125) hide show
  1. package/Cargo.lock +90 -157
  2. package/Cargo.toml +1 -0
  3. package/index.d.ts +11 -27
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.cargo/config.toml +1 -0
  13. package/sdk-core/CODEOWNERS +1 -1
  14. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
  15. package/sdk-core/bridge-ffi/src/lib.rs +311 -315
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
  17. package/sdk-core/client/Cargo.toml +13 -9
  18. package/sdk-core/client/LICENSE.txt +23 -0
  19. package/sdk-core/client/src/lib.rs +286 -174
  20. package/sdk-core/client/src/metrics.rs +86 -12
  21. package/sdk-core/client/src/raw.rs +566 -0
  22. package/sdk-core/client/src/retry.rs +137 -99
  23. package/sdk-core/core/Cargo.toml +15 -10
  24. package/sdk-core/core/LICENSE.txt +23 -0
  25. package/sdk-core/core/benches/workflow_replay.rs +79 -0
  26. package/sdk-core/core/src/abstractions.rs +38 -0
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
  29. package/sdk-core/core/src/core_tests/determinism.rs +24 -12
  30. package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
  31. package/sdk-core/core/src/core_tests/mod.rs +30 -43
  32. package/sdk-core/core/src/core_tests/queries.rs +82 -81
  33. package/sdk-core/core/src/core_tests/workers.rs +111 -296
  34. package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
  35. package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
  36. package/sdk-core/core/src/lib.rs +73 -318
  37. package/sdk-core/core/src/pollers/mod.rs +4 -6
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
  39. package/sdk-core/core/src/protosext/mod.rs +7 -10
  40. package/sdk-core/core/src/replay/mod.rs +11 -150
  41. package/sdk-core/core/src/telemetry/metrics.rs +35 -2
  42. package/sdk-core/core/src/telemetry/mod.rs +49 -16
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
  44. package/sdk-core/core/src/test_help/mod.rs +104 -170
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
  46. package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
  47. package/sdk-core/core/src/worker/activities.rs +23 -16
  48. package/sdk-core/core/src/worker/client/mocks.rs +86 -0
  49. package/sdk-core/core/src/worker/client.rs +209 -0
  50. package/sdk-core/core/src/worker/mod.rs +207 -108
  51. package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
  52. package/sdk-core/core/src/workflow/history_update.rs +107 -24
  53. package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
  54. package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
  55. package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
  56. package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
  57. package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
  58. package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
  59. package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
  60. package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
  61. package/sdk-core/core/src/workflow/mod.rs +13 -1
  62. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
  63. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
  64. package/sdk-core/core-api/Cargo.toml +9 -1
  65. package/sdk-core/core-api/LICENSE.txt +23 -0
  66. package/sdk-core/core-api/src/errors.rs +7 -38
  67. package/sdk-core/core-api/src/lib.rs +44 -52
  68. package/sdk-core/core-api/src/worker.rs +10 -2
  69. package/sdk-core/etc/deps.svg +127 -96
  70. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  73. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  80. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  81. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  84. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  85. package/sdk-core/sdk/Cargo.toml +16 -2
  86. package/sdk-core/sdk/LICENSE.txt +23 -0
  87. package/sdk-core/sdk/src/interceptors.rs +11 -0
  88. package/sdk-core/sdk/src/lib.rs +139 -151
  89. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  90. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  91. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  92. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  93. package/sdk-core/sdk-core-protos/build.rs +1 -0
  94. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  95. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  96. package/sdk-core/test-utils/Cargo.toml +3 -1
  97. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  98. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  99. package/sdk-core/test-utils/src/lib.rs +223 -68
  100. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  101. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  102. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  103. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  104. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  106. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  107. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  108. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
  109. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  110. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  111. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  112. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  113. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  114. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  115. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  116. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  117. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  118. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  119. package/sdk-core/tests/load_tests.rs +9 -6
  120. package/sdk-core/tests/main.rs +43 -10
  121. package/src/conversions.rs +7 -12
  122. package/src/lib.rs +322 -357
  123. package/sdk-core/client/src/mocks.rs +0 -167
  124. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  125. 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
- let readlock = self.runs.read();
270
- let m = readlock
271
- .get(run_id)
272
- .ok_or_else(|| WFMachinesError::Fatal("Missing workflow machines".to_string()))?;
273
- // This holds a non-async mutex across an await point which is technically a no-no, but
274
- // we never access the machines for the same run simultaneously anyway. This should all
275
- // get fixed with a generally different approach which moves the runs inside workers.
276
- let mut wfm_mutex = m.wfm.lock();
277
- let res = mutator(&mut wfm_mutex).await;
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, workflow_activation_job,
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
- ) -> Option<u32> {
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
- None
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
- gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
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.legacy_query.take().map(|q| QueryWorkflow {
321
- query_id: LEGACY_QUERY_ID.to_string(),
322
- query_type: q.query_type,
323
- arguments: Vec::from_payloads(q.query_args),
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, gateway).await {
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 {:?}", &lq);
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
- .started_attrs()
471
- .and_then(|attrs| attrs.workflow_task_timeout.clone())
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
- .request_eviction(run_id, failstr, reason)
571
- .map_or(true, |attempt| attempt <= 1);
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
- gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
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
- HistoryUpdate::new(
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
- &gateway.get_options().namespace,
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.10"
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 during initialization of [crate::Core]
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::Core::shutdown] was called, and there are no more replay tasks to be handled. Lang
26
- /// must call [crate::Core::complete_workflow_activation] for any remaining tasks, and then may
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::Core::poll_activity_task]
29
+ /// Errors thrown by [crate::Worker::poll_activity_task]
45
30
  #[derive(thiserror::Error, Debug)]
46
31
  pub enum PollActivityError {
47
- /// [crate::Core::shutdown] was called, we will no longer fetch new activity tasks. Lang must
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::Core::complete_workflow_activation]
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::Core::complete_activity_task]
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
  }