@temporalio/core-bridge 1.5.2 → 1.7.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 (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -4
  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 +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -1,7 +1,7 @@
1
1
  use crate::{AttachMetricLabels, LONG_POLL_METHOD_NAMES};
2
2
  use futures::{future::BoxFuture, FutureExt};
3
3
  use opentelemetry::{
4
- metrics::{Counter, Histogram, Meter},
4
+ metrics::{Counter, Histogram},
5
5
  KeyValue,
6
6
  };
7
7
  use std::{
@@ -30,18 +30,27 @@ pub struct MetricsContext {
30
30
  long_svc_request_latency: Histogram<u64>,
31
31
  }
32
32
 
33
+ /// Things that can provide metrics for the client implement this. Trait exists to avoid having
34
+ /// to make a whole new lower-level crate just for a tiny shared wrapper around OTel meters.
35
+ pub trait ClientMetricProvider: Send + Sync {
36
+ /// Construct a counter metric
37
+ fn counter(&self, name: &'static str) -> Counter<u64>;
38
+ /// Construct a histogram metric
39
+ fn histogram(&self, name: &'static str) -> Histogram<u64>;
40
+ }
41
+
33
42
  impl MetricsContext {
34
- pub(crate) fn new(kvs: Vec<KeyValue>, meter: &Meter) -> Self {
43
+ pub(crate) fn new(kvs: Vec<KeyValue>, metric_provider: &dyn ClientMetricProvider) -> Self {
35
44
  Self {
36
45
  ctx: opentelemetry::Context::current(),
37
46
  kvs: Arc::new(kvs),
38
47
  poll_is_long: false,
39
- svc_request: meter.u64_counter("request").init(),
40
- svc_request_failed: meter.u64_counter("request_failure").init(),
41
- long_svc_request: meter.u64_counter("long_request").init(),
42
- long_svc_request_failed: meter.u64_counter("long_request_failure").init(),
43
- svc_request_latency: meter.u64_histogram("request_latency").init(),
44
- long_svc_request_latency: meter.u64_histogram("long_request_latency").init(),
48
+ svc_request: metric_provider.counter("request"),
49
+ svc_request_failed: metric_provider.counter("request_failure"),
50
+ long_svc_request: metric_provider.counter("long_request"),
51
+ long_svc_request_failed: metric_provider.counter("long_request_failure"),
52
+ svc_request_latency: metric_provider.histogram("request_latency"),
53
+ long_svc_request_latency: metric_provider.histogram("long_request_latency"),
45
54
  }
46
55
  }
47
56
 
@@ -760,9 +760,9 @@ proxier! {
760
760
  }
761
761
  );
762
762
  (
763
- update_workflow,
764
- UpdateWorkflowRequest,
765
- UpdateWorkflowResponse,
763
+ update_workflow_execution,
764
+ UpdateWorkflowExecutionRequest,
765
+ UpdateWorkflowExecutionResponse,
766
766
  |r| {
767
767
  let labels = AttachMetricLabels::namespace(r.get_ref().namespace.clone());
768
768
  r.extensions_mut().insert(labels);
@@ -898,7 +898,7 @@ mod tests {
898
898
  let no_underscores: HashSet<_> = impl_list.iter().map(|x| x.replace('_', "")).collect();
899
899
  for method in methods {
900
900
  if !no_underscores.contains(&method.to_lowercase()) {
901
- panic!("RPC method {} is not implemented by raw client", method)
901
+ panic!("RPC method {method} is not implemented by raw client")
902
902
  }
903
903
  }
904
904
  }
@@ -1,6 +1,6 @@
1
1
  use crate::{
2
- ClientOptions, ListClosedFilters, ListOpenFilters, Namespace, Result, RetryConfig,
3
- StartTimeFilter, WorkflowClientTrait, WorkflowOptions,
2
+ ClientOptions, ListClosedFilters, ListOpenFilters, Namespace, RegisterNamespaceOptions, Result,
3
+ RetryConfig, SignalWithStartOptions, StartTimeFilter, WorkflowClientTrait, WorkflowOptions,
4
4
  };
5
5
  use backoff::{backoff::Backoff, exponential::ExponentialBackoff, Clock, SystemClock};
6
6
  use futures_retry::{ErrorHandler, FutureRetry, RetryPolicy};
@@ -8,7 +8,7 @@ use std::{fmt::Debug, future::Future, sync::Arc, time::Duration};
8
8
  use temporal_sdk_core_protos::{
9
9
  coresdk::workflow_commands::QueryResult,
10
10
  temporal::api::{
11
- common::v1::{Header, Payload, Payloads},
11
+ common::v1::{Payload, Payloads},
12
12
  enums::v1::WorkflowTaskFailedCause,
13
13
  failure::v1::Failure,
14
14
  query::v1::WorkflowQuery,
@@ -362,28 +362,14 @@ where
362
362
 
363
363
  async fn signal_with_start_workflow_execution(
364
364
  &self,
365
- input: Option<Payloads>,
366
- task_queue: String,
367
- workflow_id: String,
368
- workflow_type: String,
369
- request_id: Option<String>,
370
- options: WorkflowOptions,
371
- signal_name: String,
372
- signal_input: Option<Payloads>,
373
- signal_header: Option<Header>,
365
+ options: SignalWithStartOptions,
366
+ workflow_options: WorkflowOptions,
374
367
  ) -> Result<SignalWithStartWorkflowExecutionResponse> {
375
368
  retry_call!(
376
369
  self,
377
370
  signal_with_start_workflow_execution,
378
- input.clone(),
379
- task_queue.clone(),
380
- workflow_id.clone(),
381
- workflow_type.clone(),
382
- request_id.clone(),
383
371
  options.clone(),
384
- signal_name.clone(),
385
- signal_input.clone(),
386
- signal_header.clone()
372
+ workflow_options.clone()
387
373
  )
388
374
  }
389
375
 
@@ -473,6 +459,13 @@ where
473
459
  )
474
460
  }
475
461
 
462
+ async fn register_namespace(
463
+ &self,
464
+ options: RegisterNamespaceOptions,
465
+ ) -> Result<RegisterNamespaceResponse> {
466
+ retry_call!(self, register_namespace, options.clone())
467
+ }
468
+
476
469
  async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
477
470
  retry_call!(self, list_namespaces,)
478
471
  }
@@ -530,6 +523,25 @@ where
530
523
  )
531
524
  }
532
525
 
526
+ async fn list_archived_workflow_executions(
527
+ &self,
528
+ page_size: i32,
529
+ next_page_token: Vec<u8>,
530
+ query: String,
531
+ ) -> Result<ListArchivedWorkflowExecutionsResponse> {
532
+ retry_call!(
533
+ self,
534
+ list_archived_workflow_executions,
535
+ page_size,
536
+ next_page_token.clone(),
537
+ query.clone()
538
+ )
539
+ }
540
+
541
+ async fn get_search_attributes(&self) -> Result<GetSearchAttributesResponse> {
542
+ retry_call!(self, get_search_attributes)
543
+ }
544
+
533
545
  fn get_options(&self) -> &ClientOptions {
534
546
  self.client.get_options()
535
547
  }
@@ -12,12 +12,17 @@ categories = ["development-tools"]
12
12
 
13
13
  [lib]
14
14
 
15
+ [features]
16
+ # Do not enable this feature when building production SDKs. If we ever want a user in the field to
17
+ # record WF input data, we can build them a custom SDK or they can build - it adds significant extra
18
+ # code size in the form of [de]serializers.
19
+ save_wf_inputs = ["rmp-serde", "temporal-sdk-core-protos/serde_serialize"]
20
+
15
21
  [dependencies]
16
22
  anyhow = "1.0"
17
23
  arc-swap = "1.3"
18
- async-channel = "1.6"
19
24
  async-trait = "0.1"
20
- base64 = "0.13"
25
+ base64 = "0.21"
21
26
  crossbeam = "0.8"
22
27
  dashmap = "5.0"
23
28
  derive_builder = "0.12"
@@ -31,8 +36,7 @@ http = "0.2"
31
36
  hyper = "0.14"
32
37
  itertools = "0.10"
33
38
  lazy_static = "1.4"
34
- log = "0.4"
35
- lru = "0.8"
39
+ lru = "0.10"
36
40
  mockall = "0.11"
37
41
  nix = "0.26"
38
42
  once_cell = "1.5"
@@ -40,29 +44,31 @@ opentelemetry = { version = "0.18", features = ["rt-tokio"] }
40
44
  opentelemetry-otlp = { version = "0.11", features = ["tokio", "metrics"] }
41
45
  opentelemetry-prometheus = "0.11"
42
46
  parking_lot = { version = "0.12", features = ["send_guard"] }
47
+ pin-project = "1.0"
43
48
  prometheus = "0.13"
44
49
  prost = "0.11"
45
- prost-types = "0.11"
50
+ prost-types = { version = "0.4", package = "prost-wkt-types" }
46
51
  rand = "0.8.3"
47
52
  reqwest = { version = "0.11", features = ["json", "stream", "rustls-tls", "tokio-rustls"], default-features = false }
48
53
  ringbuf = "0.3"
54
+ rmp-serde = { version = "1.1", optional = true }
49
55
  serde = "1.0"
50
56
  serde_json = "1.0"
51
57
  siphasher = "0.3"
52
58
  slotmap = "1.0"
53
59
  tar = "0.4"
54
60
  thiserror = "1.0"
55
- tokio = { version = "1.1", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
61
+ tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
56
62
  tokio-util = { version = "0.7", features = ["io", "io-util"] }
57
63
  tokio-stream = "0.1"
58
64
  tonic = { version = "0.8", features = ["tls", "tls-roots"] }
59
- tracing = { version = "0.1", features = ["log-always"] }
65
+ tracing = "0.1"
60
66
  tracing-futures = "0.2"
61
67
  tracing-opentelemetry = "0.18"
62
68
  tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter", "registry"] }
63
69
  url = "2.2"
64
70
  uuid = { version = "1.1", features = ["v4"] }
65
- zip = "0.6"
71
+ zip = "0.6.3"
66
72
 
67
73
  # 1st party local deps
68
74
  [dependencies.temporal-sdk-core-api]
@@ -85,8 +91,9 @@ version = "0.1"
85
91
  [dev-dependencies]
86
92
  assert_matches = "1.4"
87
93
  bimap = "0.6.1"
94
+ clap = { version = "4.0", features = ["derive"] }
88
95
  criterion = "0.4"
89
- rstest = "0.16"
96
+ rstest = "0.17"
90
97
  temporal-sdk-core-test-utils = { path = "../test-utils" }
91
98
  temporal-sdk = { path = "../sdk" }
92
99
 
@@ -101,9 +108,10 @@ path = "../tests/main.rs"
101
108
  test = false
102
109
 
103
110
  [[test]]
104
- name = "load_tests"
105
- path = "../tests/load_tests.rs"
111
+ name = "heavy_tests"
112
+ path = "../tests/heavy_tests.rs"
106
113
  test = false
114
+ required-features = ["save_wf_inputs"]
107
115
 
108
116
  [[bench]]
109
117
  name = "workflow_replay"
@@ -113,4 +121,9 @@ harness = false
113
121
  # the dev-dependencies, which we want.
114
122
  [[example]]
115
123
  name = "integ_runner"
116
- path = "../tests/runner.rs"
124
+ path = "../tests/runner.rs"
125
+
126
+ [[example]]
127
+ name = "wf_input_replay"
128
+ path = "../tests/wf_input_replay.rs"
129
+ required-features = ["save_wf_inputs"]
@@ -0,0 +1,28 @@
1
+ use parking_lot::Mutex;
2
+ use std::sync::atomic::{AtomicBool, Ordering};
3
+
4
+ /// Implements something a bit like a `OnceCell`, but starts already initialized and allows you
5
+ /// to take everything out of it only once in a thread-safe way. This isn't optimized for super
6
+ /// fast-path usage.
7
+ pub struct TakeCell<T> {
8
+ taken: AtomicBool,
9
+ data: Mutex<Option<T>>,
10
+ }
11
+
12
+ impl<T> TakeCell<T> {
13
+ pub fn new(val: T) -> Self {
14
+ Self {
15
+ taken: AtomicBool::new(false),
16
+ data: Mutex::new(Some(val)),
17
+ }
18
+ }
19
+
20
+ /// If the cell has not already been taken from, takes the value and returns it
21
+ pub fn take_once(&self) -> Option<T> {
22
+ if self.taken.load(Ordering::Acquire) {
23
+ return None;
24
+ }
25
+ self.taken.store(true, Ordering::Release);
26
+ self.data.lock().take()
27
+ }
28
+ }
@@ -1,18 +1,30 @@
1
1
  //! This module contains very generic helpers that can be used codebase-wide
2
2
 
3
+ pub mod take_cell;
4
+
3
5
  use crate::MetricsContext;
6
+ use derive_more::DebugCustom;
4
7
  use futures::{stream, Stream, StreamExt};
5
8
  use std::{
6
9
  fmt::{Debug, Formatter},
7
- sync::Arc,
10
+ sync::{
11
+ atomic::{AtomicBool, AtomicUsize, Ordering},
12
+ Arc,
13
+ },
8
14
  };
9
15
  use tokio::sync::{AcquireError, OwnedSemaphorePermit, Semaphore, TryAcquireError};
16
+ use tokio_util::sync::CancellationToken;
10
17
 
11
18
  /// Wraps a [Semaphore] with a function call that is fed the available permits any time a permit is
12
19
  /// acquired or restored through the provided methods
13
20
  #[derive(Clone)]
14
21
  pub(crate) struct MeteredSemaphore {
15
22
  sem: Arc<Semaphore>,
23
+ /// The number of permit owners who have acquired a permit from the semaphore, but are not yet
24
+ /// meaningfully using that permit. This is useful for giving a more semantically accurate count
25
+ /// of used task slots, since we typically wait for a permit first before polling, but that slot
26
+ /// isn't used in the sense the user expects until we actually also get the corresponding task.
27
+ unused_claimants: Arc<AtomicUsize>,
16
28
  metrics_ctx: MetricsContext,
17
29
  record_fn: fn(&MetricsContext, usize),
18
30
  }
@@ -25,6 +37,7 @@ impl MeteredSemaphore {
25
37
  ) -> Self {
26
38
  Self {
27
39
  sem: Arc::new(Semaphore::new(inital_permits)),
40
+ unused_claimants: Arc::new(AtomicUsize::new(0)),
28
41
  metrics_ctx,
29
42
  record_fn,
30
43
  }
@@ -36,42 +49,154 @@ impl MeteredSemaphore {
36
49
 
37
50
  pub async fn acquire_owned(&self) -> Result<OwnedMeteredSemPermit, AcquireError> {
38
51
  let res = self.sem.clone().acquire_owned().await?;
39
- self.record();
40
- Ok(OwnedMeteredSemPermit {
41
- inner: res,
42
- record_fn: self.record_drop_owned(),
43
- })
52
+ Ok(self.build_owned(res))
44
53
  }
45
54
 
46
55
  pub fn try_acquire_owned(&self) -> Result<OwnedMeteredSemPermit, TryAcquireError> {
47
56
  let res = self.sem.clone().try_acquire_owned()?;
57
+ Ok(self.build_owned(res))
58
+ }
59
+
60
+ fn build_owned(&self, res: OwnedSemaphorePermit) -> OwnedMeteredSemPermit {
61
+ self.unused_claimants.fetch_add(1, Ordering::Release);
48
62
  self.record();
49
- Ok(OwnedMeteredSemPermit {
63
+ OwnedMeteredSemPermit {
50
64
  inner: res,
51
- record_fn: self.record_drop_owned(),
52
- })
65
+ unused_claimants: Some(self.unused_claimants.clone()),
66
+ record_fn: self.record_owned(),
67
+ }
53
68
  }
54
69
 
55
70
  fn record(&self) {
56
- (self.record_fn)(&self.metrics_ctx, self.sem.available_permits());
71
+ (self.record_fn)(
72
+ &self.metrics_ctx,
73
+ self.sem.available_permits() + self.unused_claimants.load(Ordering::Acquire),
74
+ );
57
75
  }
58
76
 
59
- fn record_drop_owned(&self) -> Box<dyn Fn() + Send + Sync> {
77
+ fn record_owned(&self) -> Box<dyn Fn(bool) + Send + Sync> {
60
78
  let rcf = self.record_fn;
61
79
  let mets = self.metrics_ctx.clone();
62
80
  let sem = self.sem.clone();
63
- Box::new(move || rcf(&mets, sem.available_permits() + 1))
81
+ let uc = self.unused_claimants.clone();
82
+ // When being called from the drop impl, the semaphore permit isn't actually dropped yet,
83
+ // so account for that.
84
+ Box::new(move |add_one: bool| {
85
+ let extra = usize::from(add_one);
86
+ rcf(
87
+ &mets,
88
+ sem.available_permits() + uc.load(Ordering::Acquire) + extra,
89
+ )
90
+ })
91
+ }
92
+ }
93
+
94
+ /// A version of [MeteredSemaphore] that can be closed and supports waiting for close to complete.
95
+ /// Once closed, no permits will be handed out.
96
+ /// Close completes when all permits have been returned.
97
+ pub(crate) struct ClosableMeteredSemaphore {
98
+ inner: Arc<MeteredSemaphore>,
99
+ outstanding_permits: AtomicUsize,
100
+ close_requested: AtomicBool,
101
+ close_complete_token: CancellationToken,
102
+ }
103
+
104
+ impl ClosableMeteredSemaphore {
105
+ pub fn new_arc(sem: Arc<MeteredSemaphore>) -> Arc<Self> {
106
+ Arc::new(Self {
107
+ inner: sem,
108
+ outstanding_permits: Default::default(),
109
+ close_requested: AtomicBool::new(false),
110
+ close_complete_token: CancellationToken::new(),
111
+ })
112
+ }
113
+ }
114
+
115
+ impl ClosableMeteredSemaphore {
116
+ #[cfg(test)]
117
+ pub fn available_permits(&self) -> usize {
118
+ self.inner.available_permits()
119
+ }
120
+
121
+ /// Request to close the semaphore and prevent new permits from being acquired.
122
+ pub fn close(&self) {
123
+ self.close_requested.store(true, Ordering::Release);
124
+ if self.outstanding_permits.load(Ordering::Acquire) == 0 {
125
+ self.close_complete_token.cancel();
126
+ }
127
+ }
128
+
129
+ /// Returns after close has been requested and all outstanding permits have been returned.
130
+ pub async fn close_complete(&self) {
131
+ self.close_complete_token.cancelled().await;
132
+ }
133
+
134
+ /// Acquire a permit if one is available and close was not requested.
135
+ pub fn try_acquire_owned(
136
+ self: &Arc<Self>,
137
+ ) -> Result<TrackedOwnedMeteredSemPermit, TryAcquireError> {
138
+ if self.close_requested.load(Ordering::Acquire) {
139
+ return Err(TryAcquireError::Closed);
140
+ }
141
+ self.outstanding_permits.fetch_add(1, Ordering::Release);
142
+ let res = self.inner.try_acquire_owned();
143
+ if res.is_err() {
144
+ self.outstanding_permits.fetch_sub(1, Ordering::Release);
145
+ }
146
+ res.map(|permit| TrackedOwnedMeteredSemPermit {
147
+ inner: Some(permit),
148
+ on_drop: self.on_permit_dropped(),
149
+ })
150
+ }
151
+
152
+ fn on_permit_dropped(self: &Arc<Self>) -> Box<dyn Fn() + Send + Sync> {
153
+ let sem = self.clone();
154
+ Box::new(move || {
155
+ sem.outstanding_permits.fetch_sub(1, Ordering::Release);
156
+ if sem.close_requested.load(Ordering::Acquire)
157
+ && sem.outstanding_permits.load(Ordering::Acquire) == 0
158
+ {
159
+ sem.close_complete_token.cancel();
160
+ }
161
+ })
162
+ }
163
+ }
164
+
165
+ /// Tracks an OwnedMeteredSemPermit and calls on_drop when dropped.
166
+ #[derive(DebugCustom)]
167
+ #[debug(fmt = "Tracked({inner:?})")]
168
+ pub(crate) struct TrackedOwnedMeteredSemPermit {
169
+ inner: Option<OwnedMeteredSemPermit>,
170
+ on_drop: Box<dyn Fn() + Send + Sync>,
171
+ }
172
+ impl From<TrackedOwnedMeteredSemPermit> for OwnedMeteredSemPermit {
173
+ fn from(mut value: TrackedOwnedMeteredSemPermit) -> Self {
174
+ value
175
+ .inner
176
+ .take()
177
+ .expect("Inner permit should be available")
178
+ }
179
+ }
180
+ impl Drop for TrackedOwnedMeteredSemPermit {
181
+ fn drop(&mut self) {
182
+ (self.on_drop)();
64
183
  }
65
184
  }
66
185
 
67
186
  /// Wraps an [OwnedSemaphorePermit] to update metrics when it's dropped
68
187
  pub(crate) struct OwnedMeteredSemPermit {
69
188
  inner: OwnedSemaphorePermit,
70
- record_fn: Box<dyn Fn() + Send + Sync>,
189
+ /// See [MeteredSemaphore::unused_claimants]. If present when dropping, used to decrement the
190
+ /// count.
191
+ unused_claimants: Option<Arc<AtomicUsize>>,
192
+ record_fn: Box<dyn Fn(bool) + Send + Sync>,
71
193
  }
72
194
  impl Drop for OwnedMeteredSemPermit {
73
195
  fn drop(&mut self) {
74
- (self.record_fn)()
196
+ if let Some(uc) = self.unused_claimants.take() {
197
+ uc.fetch_sub(1, Ordering::Release);
198
+ }
199
+ (self.record_fn)(true)
75
200
  }
76
201
  }
77
202
  impl Debug for OwnedMeteredSemPermit {
@@ -79,6 +204,32 @@ impl Debug for OwnedMeteredSemPermit {
79
204
  self.inner.fmt(f)
80
205
  }
81
206
  }
207
+ impl OwnedMeteredSemPermit {
208
+ /// Should be called once this permit is actually being "used" for the work it was meant to
209
+ /// permit.
210
+ pub(crate) fn into_used(mut self) -> UsedMeteredSemPermit {
211
+ if let Some(uc) = self.unused_claimants.take() {
212
+ uc.fetch_sub(1, Ordering::Release);
213
+ (self.record_fn)(false)
214
+ }
215
+ UsedMeteredSemPermit(self)
216
+ }
217
+ }
218
+
219
+ #[derive(Debug)]
220
+ pub(crate) struct UsedMeteredSemPermit(OwnedMeteredSemPermit);
221
+ impl UsedMeteredSemPermit {
222
+ #[cfg(feature = "save_wf_inputs")]
223
+ pub(crate) fn fake_deserialized() -> Self {
224
+ let sem = Arc::new(Semaphore::new(1));
225
+ let inner = sem.try_acquire_owned().unwrap();
226
+ Self(OwnedMeteredSemPermit {
227
+ inner,
228
+ unused_claimants: None,
229
+ record_fn: Box::new(|_| {}),
230
+ })
231
+ }
232
+ }
82
233
 
83
234
  /// From the input stream, create a new stream which only pulls from the input stream when allowed.
84
235
  /// When allowed is determined by the passed in `proceeder` emitting an item. The input stream is
@@ -163,4 +314,43 @@ mod tests {
163
314
  allow_tx.send(()).unwrap();
164
315
  assert_eq!(when_allowed.poll_next_unpin(&mut cx), Poll::Ready(None));
165
316
  }
317
+
318
+ #[tokio::test]
319
+ async fn closable_semaphore_permit_drop_returns_permit() {
320
+ let inner = MeteredSemaphore::new(2, MetricsContext::no_op(), |_, _| {});
321
+ let sem = ClosableMeteredSemaphore::new_arc(Arc::new(inner));
322
+ let perm = sem.try_acquire_owned().unwrap();
323
+ let permits = sem.outstanding_permits.load(Ordering::Acquire);
324
+ assert_eq!(permits, 1);
325
+ drop(perm);
326
+ let permits = sem.outstanding_permits.load(Ordering::Acquire);
327
+ assert_eq!(permits, 0);
328
+ }
329
+
330
+ #[tokio::test]
331
+ async fn closable_semaphore_permit_drop_after_close_resolves_close_complete() {
332
+ let inner = MeteredSemaphore::new(2, MetricsContext::no_op(), |_, _| {});
333
+ let sem = ClosableMeteredSemaphore::new_arc(Arc::new(inner));
334
+ let perm = sem.try_acquire_owned().unwrap();
335
+ sem.close();
336
+ drop(perm);
337
+ sem.close_complete().await;
338
+ }
339
+
340
+ #[tokio::test]
341
+ async fn closable_semaphore_close_complete_ready_if_unused() {
342
+ let inner = MeteredSemaphore::new(2, MetricsContext::no_op(), |_, _| {});
343
+ let sem = ClosableMeteredSemaphore::new_arc(Arc::new(inner));
344
+ sem.close();
345
+ sem.close_complete().await;
346
+ }
347
+
348
+ #[tokio::test]
349
+ async fn closable_semaphore_does_not_hand_out_permits_after_closed() {
350
+ let inner = MeteredSemaphore::new(2, MetricsContext::no_op(), |_, _| {});
351
+ let sem = ClosableMeteredSemaphore::new_arc(Arc::new(inner));
352
+ sem.close();
353
+ let perm = sem.try_acquire_owned().unwrap_err();
354
+ assert_matches!(perm, TryAcquireError::Closed);
355
+ }
166
356
  }