@temporalio/core-bridge 0.19.2 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) 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 +213 -241
  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 +37 -17
  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 +193 -105
  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/mod.rs +43 -33
  63. package/sdk-core/core-api/Cargo.toml +9 -1
  64. package/sdk-core/core-api/LICENSE.txt +23 -0
  65. package/sdk-core/core-api/src/errors.rs +7 -38
  66. package/sdk-core/core-api/src/lib.rs +44 -52
  67. package/sdk-core/core-api/src/worker.rs +10 -2
  68. package/sdk-core/etc/deps.svg +127 -96
  69. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  70. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  73. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  75. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  76. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  79. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  80. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  81. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  84. package/sdk-core/sdk/Cargo.toml +16 -2
  85. package/sdk-core/sdk/LICENSE.txt +23 -0
  86. package/sdk-core/sdk/src/interceptors.rs +11 -0
  87. package/sdk-core/sdk/src/lib.rs +138 -150
  88. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  89. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  90. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  91. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  92. package/sdk-core/sdk-core-protos/build.rs +1 -0
  93. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  94. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  95. package/sdk-core/test-utils/Cargo.toml +3 -1
  96. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  97. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  98. package/sdk-core/test-utils/src/lib.rs +223 -68
  99. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  100. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  101. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  102. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  103. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  104. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  106. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  107. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +8 -3
  108. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  109. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  110. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  111. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  112. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  113. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  114. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  115. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  116. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  117. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  118. package/sdk-core/tests/load_tests.rs +9 -6
  119. package/sdk-core/tests/main.rs +43 -10
  120. package/src/conversions.rs +7 -12
  121. package/src/lib.rs +322 -357
  122. package/sdk-core/client/src/mocks.rs +0 -167
  123. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  124. 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::*;
@@ -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
@@ -298,7 +295,7 @@ impl WorkflowTaskManager {
298
295
  pub(crate) async fn apply_new_poll_resp(
299
296
  &self,
300
297
  work: ValidPollWFTQResponse,
301
- gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
298
+ client: Arc<WorkerClientBag>,
302
299
  ) -> NewWfTaskOutcome {
303
300
  let mut work = if let Some(w) = self.workflow_machines.buffer_resp_if_outstanding_work(work)
304
301
  {
@@ -311,25 +308,22 @@ impl WorkflowTaskManager {
311
308
  task_token = %&work.task_token,
312
309
  history_length = %work.history.events.len(),
313
310
  attempt = %work.attempt,
311
+ run_id = %work.workflow_execution.run_id,
314
312
  "Applying new workflow task from server"
315
313
  );
316
314
  let task_start_time = Instant::now();
317
315
 
318
316
  // Check if there is a legacy query we either need to immediately issue an activation for
319
317
  // (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
- });
318
+ let legacy_query = work
319
+ .legacy_query
320
+ .take()
321
+ .map(|q| query_to_job(LEGACY_QUERY_ID.to_string(), q));
325
322
 
326
323
  let (info, mut next_activation) =
327
- match self.instantiate_or_update_workflow(work, gateway).await {
324
+ match self.instantiate_or_update_workflow(work, client).await {
328
325
  Ok((info, next_activation)) => (info, next_activation),
329
326
  Err(e) => {
330
- if let WFMachinesError::CacheMiss = e.source {
331
- return NewWfTaskOutcome::CacheMiss;
332
- }
333
327
  return NewWfTaskOutcome::Evict(e);
334
328
  }
335
329
  };
@@ -337,7 +331,7 @@ impl WorkflowTaskManager {
337
331
  // Immediately dispatch query activation if no other jobs
338
332
  let legacy_query = if next_activation.jobs.is_empty() {
339
333
  if let Some(lq) = legacy_query {
340
- debug!("Dispatching legacy query {:?}", &lq);
334
+ debug!("Dispatching legacy query {}", &lq);
341
335
  next_activation
342
336
  .jobs
343
337
  .push(workflow_activation_job::Variant::QueryWorkflow(lq).into());
@@ -467,9 +461,8 @@ impl WorkflowTaskManager {
467
461
 
468
462
  let wft_timeout: Duration = wfm
469
463
  .machines
470
- .started_attrs()
471
- .and_then(|attrs| attrs.workflow_task_timeout.clone())
472
- .and_then(|tt| tt.try_into().ok())
464
+ .get_started_info()
465
+ .and_then(|attrs| attrs.workflow_task_timeout)
473
466
  .ok_or_else(|| {
474
467
  WFMachinesError::Fatal(
475
468
  "Workflow's start attribs were missing a well formed task timeout"
@@ -584,7 +577,7 @@ impl WorkflowTaskManager {
584
577
  async fn instantiate_or_update_workflow(
585
578
  &self,
586
579
  poll_wf_resp: ValidPollWFTQResponse,
587
- gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
580
+ client: Arc<WorkerClientBag>,
588
581
  ) -> Result<(WorkflowTaskInfo, WorkflowActivation), WorkflowUpdateError> {
589
582
  let run_id = poll_wf_resp.workflow_execution.run_id.clone();
590
583
 
@@ -593,22 +586,39 @@ impl WorkflowTaskManager {
593
586
  task_token: poll_wf_resp.task_token,
594
587
  };
595
588
 
589
+ let poll_resp_is_incremental = poll_wf_resp
590
+ .history
591
+ .events
592
+ .get(0)
593
+ .map(|ev| ev.event_id > 1)
594
+ .unwrap_or_default();
595
+
596
+ let page_token = if !self.workflow_machines.exists(&run_id) && poll_resp_is_incremental {
597
+ debug!(run_id=?run_id, "Workflow task has partial history, but workflow is not in \
598
+ cache. Will fetch history");
599
+ self.metrics.sticky_cache_miss();
600
+ NextPageToken::FetchFromStart
601
+ } else {
602
+ poll_wf_resp.next_page_token.into()
603
+ };
604
+ let history_update = HistoryUpdate::new(
605
+ HistoryPaginator::new(
606
+ poll_wf_resp.history,
607
+ poll_wf_resp.workflow_execution.workflow_id.clone(),
608
+ poll_wf_resp.workflow_execution.run_id,
609
+ page_token,
610
+ client.clone(),
611
+ ),
612
+ poll_wf_resp.previous_started_event_id,
613
+ );
614
+
596
615
  match self
597
616
  .workflow_machines
598
617
  .create_or_update(
599
618
  &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
- ),
619
+ history_update,
610
620
  &poll_wf_resp.workflow_execution.workflow_id,
611
- &gateway.get_options().namespace,
621
+ client.namespace(),
612
622
  &poll_wf_resp.workflow_type,
613
623
  &self.metrics,
614
624
  )
@@ -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
  }
@@ -2,39 +2,25 @@ pub mod errors;
2
2
  pub mod worker;
3
3
 
4
4
  use crate::{
5
- errors::{
6
- CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
7
- WorkerRegistrationError,
8
- },
5
+ errors::{CompleteActivityError, CompleteWfError, PollActivityError, PollWfError},
9
6
  worker::WorkerConfig,
10
7
  };
11
8
  use log::Level;
12
- use std::{
13
- sync::Arc,
14
- time::{Duration, SystemTime, UNIX_EPOCH},
15
- };
16
- use temporal_client::ServerGatewayApis;
9
+ use opentelemetry::metrics::Meter;
10
+ use std::time::{Duration, SystemTime, UNIX_EPOCH};
17
11
  use temporal_sdk_core_protos::coresdk::{
18
12
  activity_task::ActivityTask, workflow_activation::WorkflowActivation,
19
13
  workflow_completion::WorkflowActivationCompletion, ActivityHeartbeat, ActivityTaskCompletion,
20
14
  };
21
15
 
22
- /// This trait is the primary way by which language specific SDKs interact with the core SDK. It is
23
- /// expected that only one instance of an implementation will exist for the lifetime of the
24
- /// worker(s) using it.
16
+ /// This trait is the primary way by which language specific SDKs interact with the core SDK.
17
+ /// It represents one worker, which has a (potentially shared) client for connecting to the service
18
+ /// and is bound to a specific task queue.
25
19
  #[async_trait::async_trait]
26
- pub trait Core: Send + Sync {
27
- /// Register a worker with core. Workers poll on a specific task queue, and when calling core's
28
- /// poll functions, you must provide a task queue name. If there was already a worker registered
29
- /// with the same task queue name, it will be shut down and a new one will be created.
30
- fn register_worker(&self, config: WorkerConfig) -> Result<(), WorkerRegistrationError>;
31
-
32
- /// Ask the core for some work, returning a [WorkflowActivation]. It is then the language SDK's
33
- /// responsibility to call the appropriate workflow code with the provided inputs. Blocks
34
- /// indefinitely until such work is available or [Core::shutdown] is called.
35
- ///
36
- /// The returned activation is guaranteed to be for the same task queue / worker which was
37
- /// provided as the `task_queue` argument.
20
+ pub trait Worker: Send + Sync {
21
+ /// Ask the worker for some work, returning a [WorkflowActivation]. It is then the language
22
+ /// SDK's responsibility to call the appropriate workflow code with the provided inputs. Blocks
23
+ /// indefinitely until such work is available or [Worker::shutdown] is called.
38
24
  ///
39
25
  /// It is important to understand that all activations must be responded to. There can only
40
26
  /// be one outstanding activation for a particular run of a workflow at any time. If an
@@ -48,49 +34,41 @@ pub trait Core: Send + Sync {
48
34
  ///
49
35
  /// It is rarely a good idea to call poll concurrently. It handles polling the server
50
36
  /// concurrently internally.
51
- ///
52
- /// TODO: Examples
53
- async fn poll_workflow_activation(
54
- &self,
55
- task_queue: &str,
56
- ) -> Result<WorkflowActivation, PollWfError>;
37
+ async fn poll_workflow_activation(&self) -> Result<WorkflowActivation, PollWfError>;
57
38
 
58
- /// Ask the core for some work, returning an [ActivityTask]. It is then the language SDK's
39
+ /// Ask the worker for some work, returning an [ActivityTask]. It is then the language SDK's
59
40
  /// responsibility to call the appropriate activity code with the provided inputs. Blocks
60
- /// indefinitely until such work is available or [Core::shutdown] is called.
41
+ /// indefinitely until such work is available or [Worker::shutdown] is called.
61
42
  ///
62
43
  /// The returned activation is guaranteed to be for the same task queue / worker which was
63
44
  /// provided as the `task_queue` argument.
64
45
  ///
65
46
  /// It is rarely a good idea to call poll concurrently. It handles polling the server
66
47
  /// concurrently internally.
67
- ///
68
- /// TODO: Examples
69
- async fn poll_activity_task(&self, task_queue: &str)
70
- -> Result<ActivityTask, PollActivityError>;
48
+ async fn poll_activity_task(&self) -> Result<ActivityTask, PollActivityError>;
71
49
 
72
- /// Tell the core that a workflow activation has completed. May be freely called concurrently.
50
+ /// Tell the worker that a workflow activation has completed. May be freely called concurrently.
73
51
  async fn complete_workflow_activation(
74
52
  &self,
75
53
  completion: WorkflowActivationCompletion,
76
54
  ) -> Result<(), CompleteWfError>;
77
55
 
78
- /// Tell the core that an activity has finished executing. May be freely called concurrently.
56
+ /// Tell the worker that an activity has finished executing. May be freely called concurrently.
79
57
  async fn complete_activity_task(
80
58
  &self,
81
59
  completion: ActivityTaskCompletion,
82
60
  ) -> Result<(), CompleteActivityError>;
83
61
 
84
- /// Notify workflow that an activity is still alive. Long running activities that take longer
85
- /// than `activity_heartbeat_timeout` to finish must call this function in order to report
86
- /// progress, otherwise the activity will timeout and a new attempt will be scheduled.
62
+ /// Notify the Temporal service that an activity is still alive. Long running activities that
63
+ /// take longer than `activity_heartbeat_timeout` to finish must call this function in order to
64
+ /// report progress, otherwise the activity will timeout and a new attempt will be scheduled.
87
65
  ///
88
66
  /// The first heartbeat request will be sent immediately, subsequent rapid calls to this
89
67
  /// function will result in heartbeat requests being aggregated and the last one received during
90
68
  /// the aggregation period will be sent to the server, where that period is defined as half the
91
69
  /// heartbeat timeout.
92
70
  ///
93
- /// Unlike java/go SDKs we do not return cancellation status as part of heartbeat response and
71
+ /// Unlike Java/Go SDKs we do not return cancellation status as part of heartbeat response and
94
72
  /// instead send it as a separate activity task to the lang, decoupling heartbeat and
95
73
  /// cancellation processing.
96
74
  ///
@@ -104,27 +82,36 @@ pub trait Core: Send + Sync {
104
82
 
105
83
  /// Request that a workflow be evicted by its run id. This will generate a workflow activation
106
84
  /// with the eviction job inside it to be eventually returned by
107
- /// [Core::poll_workflow_activation]. If the workflow had any existing outstanding activations,
85
+ /// [Worker::poll_workflow_activation]. If the workflow had any existing outstanding activations,
108
86
  /// such activations are invalidated and subsequent completions of them will do nothing and log
109
87
  /// a warning.
110
- fn request_workflow_eviction(&self, task_queue: &str, run_id: &str);
88
+ fn request_workflow_eviction(&self, run_id: &str);
89
+
90
+ /// Return this worker's config
91
+ fn get_config(&self) -> &WorkerConfig;
111
92
 
112
- /// Returns core's instance of the [ServerGatewayApis] implementor it is using.
113
- fn server_gateway(&self) -> Arc<dyn ServerGatewayApis + Send + Sync>;
93
+ /// TODO: Will be replaced/fixed/whatever by shutdown refactoring
94
+ fn initiate_shutdown(&self);
114
95
 
115
96
  /// Initiates async shutdown procedure, eventually ceases all polling of the server and shuts
116
- /// down all registered workers. [Core::poll_workflow_activation] should be called until it
97
+ /// down this worker. [Worker::poll_workflow_activation] should be called until it
117
98
  /// returns [PollWfError::ShutDown] to ensure that any workflows which are still undergoing
118
99
  /// replay have an opportunity to finish. This means that the lang sdk will need to call
119
- /// [Core::complete_workflow_activation] for those workflows until they are done. At that point,
120
- /// the lang SDK can end the process, or drop the [Core] instance, which will close the
100
+ /// [Worker::complete_workflow_activation] for those workflows until they are done. At that point,
101
+ /// the lang SDK can end the process, or drop the [Worker] instance, which will close the
121
102
  /// connection.
122
103
  async fn shutdown(&self);
123
104
 
124
- /// Shut down a specific worker. Will cease all polling on the task queue and future attempts
125
- /// to poll that queue will return [PollWfError::NoWorkerForQueue].
126
- async fn shutdown_worker(&self, task_queue: &str);
105
+ /// Completes shutdown and frees all resources. You should avoid simply dropping workers, as
106
+ /// this does not allow async tasks to report any panics that may have occurred cleanly.
107
+ ///
108
+ /// This should be called only after [Worker::shutdown] has resolved.
109
+ async fn finalize_shutdown(self);
110
+ }
127
111
 
112
+ /// Should be backed by a process-wide singleton who is responsible for telemetry and logging
113
+ /// management.
114
+ pub trait CoreTelemetry {
128
115
  /// Core buffers logs that should be shuttled over to lang so that they may be rendered with
129
116
  /// the user's desired logging library. Use this function to grab the most recent buffered logs
130
117
  /// since the last time it was called. A fixed number of such logs are retained at maximum, with
@@ -133,6 +120,11 @@ pub trait Core: Send + Sync {
133
120
  /// Returns the list of logs from oldest to newest. Returns an empty vec if the feature is not
134
121
  /// configured.
135
122
  fn fetch_buffered_logs(&self) -> Vec<CoreLog>;
123
+
124
+ /// If metrics gathering is enabled, returns the OTel meter for core telemetry, which can be
125
+ /// used to create metrics instruments, or passed to things that create/record metrics (ex:
126
+ /// clients).
127
+ fn get_metric_meter(&self) -> Option<&Meter>;
136
128
  }
137
129
 
138
130
  /// A log line (which ultimately came from a tracing event) exported from Core->Lang
@@ -4,8 +4,9 @@ use std::time::Duration;
4
4
  #[derive(Debug, Clone, derive_builder::Builder)]
5
5
  #[builder(setter(into), build_fn(validate = "Self::validate"))]
6
6
  #[non_exhaustive]
7
- // TODO: per-second queue limits
8
7
  pub struct WorkerConfig {
8
+ /// The Temporal service namespace this worker is bound to
9
+ pub namespace: String,
9
10
  /// What task queue will this worker poll from? This task queue name will be used for both
10
11
  /// workflow and activity polling.
11
12
  pub task_queue: String,
@@ -45,7 +46,7 @@ pub struct WorkerConfig {
45
46
  #[builder(default = "5")]
46
47
  pub max_concurrent_at_polls: usize,
47
48
  /// If set to true this worker will only handle workflow tasks and local activities, it will not
48
- /// poll for activity tasks. This option exists because
49
+ /// poll for activity tasks.
49
50
  #[builder(default = "false")]
50
51
  pub no_remote_activities: bool,
51
52
  /// How long a workflow task is allowed to sit on the sticky queue before it is timed out
@@ -63,6 +64,13 @@ pub struct WorkerConfig {
63
64
  /// `heartbeat_timeout * 0.8`.
64
65
  #[builder(default = "Duration::from_secs(30)")]
65
66
  pub default_heartbeat_throttle_interval: Duration,
67
+
68
+ /// Sets the maximum number of activities per second the task queue will dispatch, controlled
69
+ /// server-side. Note that this only takes effect upon an activity poll request. If multiple
70
+ /// workers on the same queue have different values set, they will thrash with the last poller
71
+ /// winning.
72
+ #[builder(setter(strip_option), default)]
73
+ pub max_task_queue_activities_per_second: Option<f64>,
66
74
  }
67
75
 
68
76
  impl WorkerConfig {