@temporalio/core-bridge 1.5.2 → 1.6.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 (153) hide show
  1. package/Cargo.lock +255 -48
  2. package/package.json +4 -4
  3. package/releases/aarch64-apple-darwin/index.node +0 -0
  4. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  5. package/releases/x86_64-apple-darwin/index.node +0 -0
  6. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  7. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  8. package/sdk-core/.buildkite/pipeline.yml +1 -3
  9. package/sdk-core/.cargo/config.toml +5 -2
  10. package/sdk-core/.github/workflows/heavy.yml +28 -0
  11. package/sdk-core/Cargo.toml +1 -1
  12. package/sdk-core/README.md +9 -5
  13. package/sdk-core/client/src/lib.rs +211 -36
  14. package/sdk-core/client/src/raw.rs +1 -1
  15. package/sdk-core/client/src/retry.rs +32 -20
  16. package/sdk-core/core/Cargo.toml +23 -9
  17. package/sdk-core/core/src/abstractions.rs +11 -0
  18. package/sdk-core/core/src/core_tests/activity_tasks.rs +6 -5
  19. package/sdk-core/core/src/core_tests/local_activities.rs +263 -22
  20. package/sdk-core/core/src/core_tests/queries.rs +2 -2
  21. package/sdk-core/core/src/core_tests/workflow_tasks.rs +249 -5
  22. package/sdk-core/core/src/ephemeral_server/mod.rs +5 -6
  23. package/sdk-core/core/src/lib.rs +2 -0
  24. package/sdk-core/core/src/protosext/mod.rs +1 -1
  25. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  26. package/sdk-core/core/src/telemetry/mod.rs +23 -8
  27. package/sdk-core/core/src/test_help/mod.rs +8 -1
  28. package/sdk-core/core/src/worker/activities/local_activities.rs +259 -125
  29. package/sdk-core/core/src/worker/activities.rs +3 -2
  30. package/sdk-core/core/src/worker/mod.rs +53 -26
  31. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  32. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  33. package/sdk-core/core/src/worker/workflow/history_update.rs +835 -277
  34. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -17
  35. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +3 -5
  36. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -2
  37. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +3 -5
  38. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -2
  39. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -2
  40. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -2
  41. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +73 -51
  42. package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -3
  43. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -4
  44. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -2
  45. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +3 -5
  46. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +6 -7
  47. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  48. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -4
  49. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  50. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +89 -58
  51. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -7
  52. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +21 -9
  53. package/sdk-core/core/src/worker/workflow/managed_run.rs +1021 -360
  54. package/sdk-core/core/src/worker/workflow/mod.rs +306 -346
  55. package/sdk-core/core/src/worker/workflow/run_cache.rs +29 -53
  56. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  57. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  58. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +115 -0
  59. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  60. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +444 -714
  61. package/sdk-core/core-api/Cargo.toml +2 -0
  62. package/sdk-core/core-api/src/errors.rs +1 -34
  63. package/sdk-core/core-api/src/lib.rs +6 -2
  64. package/sdk-core/core-api/src/worker.rs +14 -1
  65. package/sdk-core/etc/deps.svg +115 -140
  66. package/sdk-core/etc/regen-depgraph.sh +5 -0
  67. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -6
  68. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -3
  69. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  70. package/sdk-core/protos/api_upstream/Makefile +5 -5
  71. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  72. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  73. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  74. package/sdk-core/protos/api_upstream/go.mod +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  76. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +12 -19
  77. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
  78. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  79. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -2
  80. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  81. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +3 -3
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -2
  83. package/sdk-core/protos/api_upstream/temporal/api/{update/v1/message.proto → enums/v1/interaction_type.proto} +11 -18
  84. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  85. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  86. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  87. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  88. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  89. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +2 -13
  90. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  91. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  92. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  93. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  94. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -19
  95. package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -2
  98. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  101. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  103. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +13 -8
  106. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  107. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  108. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  109. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  110. package/sdk-core/sdk/Cargo.toml +4 -3
  111. package/sdk-core/sdk/src/lib.rs +87 -21
  112. package/sdk-core/sdk/src/workflow_future.rs +7 -12
  113. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  114. package/sdk-core/sdk-core-protos/build.rs +36 -2
  115. package/sdk-core/sdk-core-protos/src/history_builder.rs +26 -19
  116. package/sdk-core/sdk-core-protos/src/history_info.rs +4 -0
  117. package/sdk-core/sdk-core-protos/src/lib.rs +78 -34
  118. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  119. package/sdk-core/test-utils/Cargo.toml +3 -1
  120. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  121. package/sdk-core/test-utils/src/lib.rs +50 -18
  122. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  123. package/sdk-core/test-utils/src/workflows.rs +29 -0
  124. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  125. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +114 -7
  126. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -2
  127. package/sdk-core/tests/integ_tests/metrics_tests.rs +1 -1
  128. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -39
  129. package/sdk-core/tests/integ_tests/queries_tests.rs +2 -127
  130. package/sdk-core/tests/integ_tests/visibility_tests.rs +52 -5
  131. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +74 -1
  132. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +5 -13
  133. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +1 -1
  134. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +2 -10
  135. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +69 -197
  136. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +4 -28
  137. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  138. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +14 -14
  139. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -19
  140. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -19
  141. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests.rs +5 -6
  143. package/sdk-core/tests/main.rs +2 -12
  144. package/sdk-core/tests/runner.rs +71 -34
  145. package/sdk-core/tests/wf_input_replay.rs +32 -0
  146. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  147. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  148. package/sdk-core/bridge-ffi/build.rs +0 -25
  149. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  150. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  151. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  152. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  153. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -1,22 +1,20 @@
1
1
  use crate::{
2
2
  telemetry::metrics::workflow_type,
3
3
  worker::workflow::{
4
- managed_run::WorkflowManager, HistoryUpdate, LocalActivityRequestSink, ManagedRunHandle,
5
- NewIncomingWFT, RunUpdateResponse,
4
+ managed_run::{ManagedRun, RunUpdateAct},
5
+ HistoryUpdate, LocalActivityRequestSink, PermittedWFT,
6
6
  },
7
7
  MetricsContext,
8
8
  };
9
9
  use lru::LruCache;
10
- use std::{num::NonZeroUsize, time::Instant};
11
- use tokio::sync::mpsc::UnboundedSender;
10
+ use std::{mem, num::NonZeroUsize, sync::Arc};
12
11
 
13
12
  pub(super) struct RunCache {
14
13
  max: usize,
15
14
  namespace: String,
16
- run_update_tx: UnboundedSender<RunUpdateResponse>,
17
15
  /// Run id -> Data
18
- runs: LruCache<String, ManagedRunHandle>,
19
- local_activity_request_sink: LocalActivityRequestSink,
16
+ runs: LruCache<String, ManagedRun>,
17
+ local_activity_request_sink: Arc<dyn LocalActivityRequestSink>,
20
18
 
21
19
  metrics: MetricsContext,
22
20
  }
@@ -25,8 +23,7 @@ impl RunCache {
25
23
  pub fn new(
26
24
  max_cache_size: usize,
27
25
  namespace: String,
28
- run_update_tx: UnboundedSender<RunUpdateResponse>,
29
- local_activity_request_sink: LocalActivityRequestSink,
26
+ local_activity_request_sink: Arc<dyn LocalActivityRequestSink>,
30
27
  metrics: MetricsContext,
31
28
  ) -> Self {
32
29
  // The cache needs room for at least one run, otherwise we couldn't do anything. In
@@ -39,7 +36,6 @@ impl RunCache {
39
36
  Self {
40
37
  max: max_cache_size,
41
38
  namespace,
42
- run_update_tx,
43
39
  runs: LruCache::new(
44
40
  NonZeroUsize::new(lru_size).expect("LRU size is guaranteed positive"),
45
41
  ),
@@ -48,71 +44,51 @@ impl RunCache {
48
44
  }
49
45
  }
50
46
 
51
- pub fn instantiate_or_update(
52
- &mut self,
53
- run_id: &str,
54
- workflow_id: &str,
55
- wf_type: &str,
56
- history_update: HistoryUpdate,
57
- start_time: Instant,
58
- ) -> &mut ManagedRunHandle {
47
+ pub fn instantiate_or_update(&mut self, mut pwft: PermittedWFT) -> RunUpdateAct {
59
48
  let cur_num_cached_runs = self.runs.len();
49
+ let run_id = &pwft.work.execution.run_id;
60
50
 
61
- if self.runs.contains(run_id) {
62
- // For some weird reason, maybe a NLL bug, there are double-mutable-borrow errors if I
63
- // use get_mut above instead of in here (even though we always return from this branch).
64
- // So, forced to do this.
65
- let run_handle = self.runs.get_mut(run_id).unwrap();
66
-
67
- run_handle.metrics.sticky_cache_hit();
68
- run_handle.incoming_wft(NewIncomingWFT {
69
- history_update: Some(history_update),
70
- start_time,
71
- });
51
+ if let Some(run_handle) = self.runs.get_mut(run_id) {
52
+ let rur = run_handle.incoming_wft(pwft);
72
53
  self.metrics.cache_size(cur_num_cached_runs as u64);
73
- return run_handle;
54
+ return rur;
74
55
  }
75
56
 
76
57
  // Create a new workflow machines instance for this workflow, initialize it, and
77
58
  // track it.
78
59
  let metrics = self
79
60
  .metrics
80
- .with_new_attrs([workflow_type(wf_type.to_string())]);
81
- let wfm = WorkflowManager::new(
61
+ .with_new_attrs([workflow_type(pwft.work.workflow_type.clone())]);
62
+ // Replace the update in the wft with a dummy one, since we must instantiate the machines
63
+ // with the update.
64
+ let history_update = mem::replace(&mut pwft.work.update, HistoryUpdate::dummy());
65
+ let mut mrh = ManagedRun::new(
82
66
  history_update,
83
67
  self.namespace.clone(),
84
- workflow_id.to_string(),
85
- wf_type.to_string(),
86
- run_id.to_string(),
87
- metrics.clone(),
88
- );
89
- let mut mrh = ManagedRunHandle::new(
90
- wfm,
91
- self.run_update_tx.clone(),
68
+ pwft.work.execution.workflow_id.clone(),
69
+ pwft.work.workflow_type.clone(),
70
+ pwft.work.execution.run_id.clone(),
92
71
  self.local_activity_request_sink.clone(),
93
72
  metrics,
94
73
  );
95
- mrh.incoming_wft(NewIncomingWFT {
96
- history_update: None,
97
- start_time,
98
- });
99
- if self.runs.push(run_id.to_string(), mrh).is_some() {
74
+ let run_id = run_id.to_string();
75
+ let rur = mrh.incoming_wft(pwft);
76
+ if self.runs.push(run_id, mrh).is_some() {
100
77
  panic!("Overflowed run cache! Cache owner is expected to avoid this!");
101
78
  }
102
79
  self.metrics.cache_size(cur_num_cached_runs as u64 + 1);
103
- // This is safe, we just inserted.
104
- self.runs.get_mut(run_id).unwrap()
80
+ rur
105
81
  }
106
- pub fn remove(&mut self, k: &str) -> Option<ManagedRunHandle> {
82
+ pub fn remove(&mut self, k: &str) -> Option<ManagedRun> {
107
83
  let r = self.runs.pop(k);
108
84
  self.metrics.cache_size(self.len() as u64);
109
85
  r
110
86
  }
111
87
 
112
- pub fn get_mut(&mut self, k: &str) -> Option<&mut ManagedRunHandle> {
88
+ pub fn get_mut(&mut self, k: &str) -> Option<&mut ManagedRun> {
113
89
  self.runs.get_mut(k)
114
90
  }
115
- pub fn get(&mut self, k: &str) -> Option<&ManagedRunHandle> {
91
+ pub fn get(&mut self, k: &str) -> Option<&ManagedRun> {
116
92
  self.runs.get(k)
117
93
  }
118
94
 
@@ -121,16 +97,16 @@ impl RunCache {
121
97
  self.runs.peek_lru().map(|(run_id, _)| run_id.as_str())
122
98
  }
123
99
  /// Returns an iterator yielding cached runs in LRU order
124
- pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &ManagedRunHandle)> {
100
+ pub fn runs_lru_order(&self) -> impl Iterator<Item = (&str, &ManagedRun)> {
125
101
  self.runs.iter().rev().map(|(k, v)| (k.as_str(), v))
126
102
  }
127
- pub fn peek(&self, k: &str) -> Option<&ManagedRunHandle> {
103
+ pub fn peek(&self, k: &str) -> Option<&ManagedRun> {
128
104
  self.runs.peek(k)
129
105
  }
130
106
  pub fn has_run(&self, k: &str) -> bool {
131
107
  self.runs.contains(k)
132
108
  }
133
- pub fn handles(&self) -> impl Iterator<Item = &ManagedRunHandle> {
109
+ pub fn handles(&self) -> impl Iterator<Item = &ManagedRun> {
134
110
  self.runs.iter().map(|(_, v)| v)
135
111
  }
136
112
  pub fn is_full(&self) -> bool {
@@ -0,0 +1,125 @@
1
+ use crate::{
2
+ abstractions::OwnedMeteredSemPermit,
3
+ protosext::ValidPollWFTQResponse,
4
+ worker::{
5
+ client::WorkerClient,
6
+ workflow::{
7
+ history_update::HistoryPaginator, CacheMissFetchReq, HistoryUpdate, NextPageReq,
8
+ PermittedWFT,
9
+ },
10
+ },
11
+ };
12
+ use futures::Stream;
13
+ use futures_util::{stream, stream::PollNext, FutureExt, StreamExt};
14
+ use std::{future, sync::Arc};
15
+ use tracing::Span;
16
+
17
+ /// Transforms incoming validated WFTs and history fetching requests into [PermittedWFT]s ready
18
+ /// for application to workflow state
19
+ pub(super) struct WFTExtractor {}
20
+
21
+ pub(super) enum WFTExtractorOutput {
22
+ NewWFT(PermittedWFT),
23
+ FetchResult(PermittedWFT, Arc<HistfetchRC>),
24
+ NextPage {
25
+ paginator: HistoryPaginator,
26
+ update: HistoryUpdate,
27
+ span: Span,
28
+ rc: Arc<HistfetchRC>,
29
+ },
30
+ FailedFetch {
31
+ run_id: String,
32
+ err: tonic::Status,
33
+ },
34
+ PollerDead,
35
+ }
36
+
37
+ type WFTStreamIn = (
38
+ Result<ValidPollWFTQResponse, tonic::Status>,
39
+ OwnedMeteredSemPermit,
40
+ );
41
+ #[derive(derive_more::From, Debug)]
42
+ pub(super) enum HistoryFetchReq {
43
+ Full(CacheMissFetchReq, Arc<HistfetchRC>),
44
+ NextPage(NextPageReq, Arc<HistfetchRC>),
45
+ }
46
+ /// Used inside of `Arc`s to ensure we don't shutdown while there are outstanding fetches.
47
+ #[derive(Debug)]
48
+ pub(super) struct HistfetchRC {}
49
+
50
+ impl WFTExtractor {
51
+ pub(super) fn build(
52
+ client: Arc<dyn WorkerClient>,
53
+ max_fetch_concurrency: usize,
54
+ wft_stream: impl Stream<Item = WFTStreamIn> + Send + 'static,
55
+ fetch_stream: impl Stream<Item = HistoryFetchReq> + Send + 'static,
56
+ ) -> impl Stream<Item = Result<WFTExtractorOutput, tonic::Status>> + Send + 'static {
57
+ let fetch_client = client.clone();
58
+ let wft_stream = wft_stream
59
+ .map(move |(wft, permit)| {
60
+ let client = client.clone();
61
+ async move {
62
+ match wft {
63
+ Ok(wft) => {
64
+ let run_id = wft.workflow_execution.run_id.clone();
65
+ Ok(match HistoryPaginator::from_poll(wft, client).await {
66
+ Ok((pag, prep)) => WFTExtractorOutput::NewWFT(PermittedWFT {
67
+ work: prep,
68
+ permit,
69
+ paginator: pag,
70
+ }),
71
+ Err(err) => WFTExtractorOutput::FailedFetch { run_id, err },
72
+ })
73
+ }
74
+ Err(e) => Err(e),
75
+ }
76
+ }
77
+ // This is... unattractive, but lets us avoid boxing all the futs in the stream
78
+ .left_future()
79
+ .left_future()
80
+ })
81
+ .chain(stream::iter([future::ready(Ok(
82
+ WFTExtractorOutput::PollerDead,
83
+ ))
84
+ .right_future()
85
+ .left_future()]));
86
+
87
+ stream::select_with_strategy(
88
+ wft_stream,
89
+ fetch_stream.map(move |fetchreq: HistoryFetchReq| {
90
+ let client = fetch_client.clone();
91
+ async move {
92
+ Ok(match fetchreq {
93
+ // It's OK to simply drop the refcounters in the event of fetch
94
+ // failure. We'll just proceed with shutdown.
95
+ HistoryFetchReq::Full(req, rc) => {
96
+ let run_id = req.original_wft.work.execution.run_id.clone();
97
+ match HistoryPaginator::from_fetchreq(req, client).await {
98
+ Ok(r) => WFTExtractorOutput::FetchResult(r, rc),
99
+ Err(err) => WFTExtractorOutput::FailedFetch { run_id, err },
100
+ }
101
+ }
102
+ HistoryFetchReq::NextPage(mut req, rc) => {
103
+ match req.paginator.extract_next_update().await {
104
+ Ok(update) => WFTExtractorOutput::NextPage {
105
+ paginator: req.paginator,
106
+ update,
107
+ span: req.span,
108
+ rc,
109
+ },
110
+ Err(err) => WFTExtractorOutput::FailedFetch {
111
+ run_id: req.paginator.run_id,
112
+ err,
113
+ },
114
+ }
115
+ }
116
+ })
117
+ }
118
+ .right_future()
119
+ }),
120
+ // Priority always goes to the fetching stream
121
+ |_: &mut ()| PollNext::Right,
122
+ )
123
+ .buffer_unordered(max_fetch_concurrency)
124
+ }
125
+ }
@@ -47,10 +47,7 @@ pub(crate) fn validate_wft(
47
47
  wft.try_into().map_err(|resp| {
48
48
  tonic::Status::new(
49
49
  tonic::Code::DataLoss,
50
- format!(
51
- "Server returned a poll WFT response we couldn't interpret: {:?}",
52
- resp
53
- ),
50
+ format!("Server returned a poll WFT response we couldn't interpret: {resp:?}"),
54
51
  )
55
52
  })
56
53
  }
@@ -0,0 +1,115 @@
1
+ use crate::{
2
+ telemetry::metrics::MetricsContext,
3
+ worker::{
4
+ workflow::{
5
+ workflow_stream::{WFStream, WFStreamInput},
6
+ LAReqSink, LocalActivityRequestSink,
7
+ },
8
+ LocalActRequest, LocalActivityResolution,
9
+ },
10
+ };
11
+ use crossbeam::queue::SegQueue;
12
+ use futures::Stream;
13
+ use futures_util::StreamExt;
14
+ use serde::{Deserialize, Serialize};
15
+ use std::{future, sync::Arc};
16
+ use temporal_sdk_core_api::worker::WorkerConfig;
17
+ use tokio::sync::mpsc::UnboundedSender;
18
+ use tokio_util::sync::CancellationToken;
19
+
20
+ /// Replay everything that happened to internal workflow state. Useful for 100% deterministic
21
+ /// reproduction of bugs.
22
+ ///
23
+ /// Use `CoreWfStarter::enable_wf_state_input_recording` from the integration test utilities to
24
+ /// activate saving the data to disk, and use the `wf_input_replay` example binary to replay.
25
+ pub async fn replay_wf_state_inputs(mut config: WorkerConfig, inputs: impl Stream<Item = Vec<u8>>) {
26
+ use crate::worker::build_wf_basics;
27
+
28
+ let la_resp_q = Arc::new(SegQueue::new());
29
+ let la_resp_q_clone = la_resp_q.clone();
30
+ let inputs = inputs
31
+ .map(|bytes| {
32
+ rmp_serde::from_slice::<StoredWFStateInputDeSer>(&bytes)
33
+ .expect("Can decode wf stream input")
34
+ })
35
+ .filter_map(|si| {
36
+ future::ready(match si {
37
+ StoredWFStateInputDeSer::Stream(wfsi) => Some(wfsi),
38
+ StoredWFStateInputDeSer::ImmediateLASinkResolutions(lares) => {
39
+ la_resp_q_clone.push(lares);
40
+ None
41
+ }
42
+ })
43
+ });
44
+ let basics = build_wf_basics(
45
+ &mut config,
46
+ MetricsContext::no_op(),
47
+ CancellationToken::new(),
48
+ );
49
+ let sink = ReadingFromFileLaReqSink {
50
+ resolutions: la_resp_q,
51
+ };
52
+ info!("Beginning workflow stream internal state replay");
53
+ let stream = WFStream::build_internal(inputs, basics, sink);
54
+ stream
55
+ .for_each(|o| async move { trace!("Stream output: {:?}", o) })
56
+ .await;
57
+ }
58
+
59
+ impl WFStream {
60
+ pub(super) fn prep_input(&mut self, action: &WFStreamInput) -> Option<PreppedInputWrite> {
61
+ // Remove the channel, we'll put it back, avoiding a clone
62
+ self.wf_state_inputs.take().map(|chan| PreppedInputWrite {
63
+ data: rmp_serde::to_vec(&StoredWFStateInputSer::Stream(action))
64
+ .expect("WF Inputs are serializable"),
65
+ chan,
66
+ })
67
+ }
68
+ pub(super) fn flush_write(&mut self, w: PreppedInputWrite) {
69
+ let _ = w.chan.send(w.data);
70
+ self.wf_state_inputs = Some(w.chan);
71
+ }
72
+ }
73
+ pub(super) struct PreppedInputWrite {
74
+ data: Vec<u8>,
75
+ chan: UnboundedSender<Vec<u8>>,
76
+ }
77
+
78
+ #[derive(Serialize)]
79
+ enum StoredWFStateInputSer<'a> {
80
+ Stream(&'a WFStreamInput),
81
+ ImmediateLASinkResolutions(&'a Vec<LocalActivityResolution>),
82
+ }
83
+
84
+ #[derive(Deserialize)]
85
+ enum StoredWFStateInputDeSer {
86
+ Stream(WFStreamInput),
87
+ ImmediateLASinkResolutions(Vec<LocalActivityResolution>),
88
+ }
89
+
90
+ struct ReadingFromFileLaReqSink {
91
+ resolutions: Arc<SegQueue<Vec<LocalActivityResolution>>>,
92
+ }
93
+ impl LocalActivityRequestSink for ReadingFromFileLaReqSink {
94
+ fn sink_reqs(&self, reqs: Vec<LocalActRequest>) -> Vec<LocalActivityResolution> {
95
+ if !reqs.is_empty() {
96
+ self.resolutions
97
+ .pop()
98
+ .expect("LA sink was called, but there's no stored immediate response")
99
+ } else {
100
+ vec![]
101
+ }
102
+ }
103
+ }
104
+
105
+ impl LAReqSink {
106
+ pub(crate) fn write_req(&self, res: &Vec<LocalActivityResolution>) {
107
+ if let Some(r) = self.recorder.as_ref() {
108
+ r.send(
109
+ rmp_serde::to_vec(&StoredWFStateInputSer::ImmediateLASinkResolutions(res))
110
+ .expect("LA immediate resolutions are serializable"),
111
+ )
112
+ .expect("WF input serialization channel is available for immediate LA result storage");
113
+ }
114
+ }
115
+ }
@@ -0,0 +1,24 @@
1
+ use tonic::{Code, Status};
2
+
3
+ #[derive(serde::Serialize, serde::Deserialize)]
4
+ #[serde(remote = "Status")]
5
+ pub(super) struct SerdeStatus {
6
+ #[serde(getter = "get_code")]
7
+ code: i32,
8
+ #[serde(getter = "get_owned_msg")]
9
+ message: String,
10
+ }
11
+
12
+ fn get_owned_msg(v: &Status) -> String {
13
+ v.message().to_string()
14
+ }
15
+
16
+ fn get_code(v: &Status) -> i32 {
17
+ v.code() as i32
18
+ }
19
+
20
+ impl From<SerdeStatus> for Status {
21
+ fn from(v: SerdeStatus) -> Self {
22
+ Status::new(Code::from(v.code), v.message)
23
+ }
24
+ }