@temporalio/core-bridge 1.4.4 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +327 -419
- package/Cargo.toml +1 -1
- package/index.js +25 -2
- package/lib/errors.d.ts +22 -0
- package/lib/errors.js +65 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +440 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/package.json +11 -5
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
- package/sdk-core/bridge-ffi/Cargo.toml +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -25
- package/sdk-core/bridge-ffi/src/lib.rs +29 -108
- package/sdk-core/bridge-ffi/src/wrappers.rs +35 -25
- package/sdk-core/client/Cargo.toml +1 -1
- package/sdk-core/client/src/lib.rs +12 -20
- package/sdk-core/client/src/raw.rs +9 -8
- package/sdk-core/client/src/retry.rs +100 -23
- package/sdk-core/core/Cargo.toml +5 -5
- package/sdk-core/core/benches/workflow_replay.rs +13 -10
- package/sdk-core/core/src/abstractions.rs +22 -22
- package/sdk-core/core/src/core_tests/activity_tasks.rs +1 -1
- package/sdk-core/core/src/core_tests/local_activities.rs +228 -6
- package/sdk-core/core/src/core_tests/queries.rs +247 -89
- package/sdk-core/core/src/core_tests/workers.rs +2 -2
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +46 -27
- package/sdk-core/core/src/lib.rs +139 -32
- package/sdk-core/core/src/replay/mod.rs +185 -41
- package/sdk-core/core/src/telemetry/log_export.rs +190 -0
- package/sdk-core/core/src/telemetry/metrics.rs +184 -139
- package/sdk-core/core/src/telemetry/mod.rs +296 -318
- package/sdk-core/core/src/telemetry/prometheus_server.rs +4 -3
- package/sdk-core/core/src/test_help/mod.rs +9 -7
- package/sdk-core/core/src/worker/activities/local_activities.rs +2 -1
- package/sdk-core/core/src/worker/activities.rs +40 -23
- package/sdk-core/core/src/worker/client/mocks.rs +1 -1
- package/sdk-core/core/src/worker/client.rs +30 -4
- package/sdk-core/core/src/worker/mod.rs +22 -18
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +10 -19
- package/sdk-core/core/src/worker/workflow/history_update.rs +99 -25
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +2 -6
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +18 -21
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -38
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +8 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +232 -216
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -6
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +4 -4
- package/sdk-core/core/src/worker/workflow/managed_run.rs +13 -5
- package/sdk-core/core/src/worker/workflow/mod.rs +61 -9
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +56 -11
- package/sdk-core/core-api/Cargo.toml +4 -3
- package/sdk-core/core-api/src/lib.rs +1 -43
- package/sdk-core/core-api/src/telemetry.rs +147 -0
- package/sdk-core/core-api/src/worker.rs +13 -0
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
- package/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
- package/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
- package/sdk-core/protos/api_upstream/buf.yaml +0 -3
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +3 -7
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +8 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +19 -59
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -19
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +108 -29
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +47 -8
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +15 -1
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +8 -1
- package/sdk-core/sdk/src/interceptors.rs +36 -3
- package/sdk-core/sdk/src/lib.rs +7 -4
- package/sdk-core/sdk/src/workflow_context.rs +13 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +47 -1
- package/sdk-core/sdk-core-protos/src/history_info.rs +22 -22
- package/sdk-core/sdk-core-protos/src/lib.rs +49 -27
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/test-utils/src/lib.rs +81 -29
- package/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
- package/sdk-core/tests/integ_tests/polling_tests.rs +0 -13
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +145 -4
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +106 -20
- package/sdk-core/tests/integ_tests/workflow_tests.rs +18 -8
- package/sdk-core/tests/main.rs +6 -4
- package/src/conversions.rs +52 -47
- package/src/errors.rs +28 -86
- package/src/helpers.rs +3 -4
- package/src/lib.rs +2 -2
- package/src/runtime.rs +132 -61
- package/src/testing.rs +7 -4
- package/src/worker.rs +67 -50
- package/ts/errors.ts +55 -0
- package/{index.d.ts → ts/index.ts} +121 -15
- package/sdk-core/core/src/log_export.rs +0 -62
- package/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
- package/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
- package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +0 -40
|
@@ -101,32 +101,49 @@ impl<SG> RetryClient<SG> {
|
|
|
101
101
|
F: FnMut() -> Fut + Unpin,
|
|
102
102
|
Fut: Future<Output = Result<R>>,
|
|
103
103
|
{
|
|
104
|
-
FutureRetry::new(
|
|
104
|
+
FutureRetry::new(
|
|
105
|
+
factory,
|
|
106
|
+
TonicErrorHandler::new(rtc, RetryConfig::throttle_retry_policy(), call_name),
|
|
107
|
+
)
|
|
105
108
|
}
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
#[derive(Debug)]
|
|
109
112
|
pub(crate) struct TonicErrorHandler<C: Clock> {
|
|
110
113
|
backoff: ExponentialBackoff<C>,
|
|
114
|
+
throttle_backoff: ExponentialBackoff<C>,
|
|
111
115
|
max_retries: usize,
|
|
112
116
|
call_type: CallType,
|
|
113
117
|
call_name: &'static str,
|
|
114
118
|
}
|
|
115
119
|
impl TonicErrorHandler<SystemClock> {
|
|
116
|
-
fn new(cfg: RetryConfig, call_name: &'static str) -> Self {
|
|
117
|
-
Self::new_with_clock(
|
|
120
|
+
fn new(cfg: RetryConfig, throttle_cfg: RetryConfig, call_name: &'static str) -> Self {
|
|
121
|
+
Self::new_with_clock(
|
|
122
|
+
cfg,
|
|
123
|
+
throttle_cfg,
|
|
124
|
+
call_name,
|
|
125
|
+
SystemClock::default(),
|
|
126
|
+
SystemClock::default(),
|
|
127
|
+
)
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
impl<C> TonicErrorHandler<C>
|
|
121
131
|
where
|
|
122
132
|
C: Clock,
|
|
123
133
|
{
|
|
124
|
-
fn new_with_clock(
|
|
134
|
+
fn new_with_clock(
|
|
135
|
+
cfg: RetryConfig,
|
|
136
|
+
throttle_cfg: RetryConfig,
|
|
137
|
+
call_name: &'static str,
|
|
138
|
+
clock: C,
|
|
139
|
+
throttle_clock: C,
|
|
140
|
+
) -> Self {
|
|
125
141
|
Self {
|
|
126
142
|
max_retries: cfg.max_retries,
|
|
127
143
|
call_type: CallType::from_call_name(call_name),
|
|
128
144
|
call_name,
|
|
129
145
|
backoff: cfg.into_exp_backoff(clock),
|
|
146
|
+
throttle_backoff: throttle_cfg.into_exp_backoff(throttle_clock),
|
|
130
147
|
}
|
|
131
148
|
}
|
|
132
149
|
const fn should_log_retry_warning(&self, cur_attempt: usize) -> bool {
|
|
@@ -184,10 +201,12 @@ where
|
|
|
184
201
|
match self.backoff.next_backoff() {
|
|
185
202
|
None => RetryPolicy::ForwardError(e), // None is returned when we've ran out of time
|
|
186
203
|
Some(backoff) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
204
|
+
// We treat ResourceExhausted as a special case and backoff more
|
|
205
|
+
// so we don't overload the server
|
|
206
|
+
if e.code() == Code::ResourceExhausted {
|
|
207
|
+
let extended_backoff =
|
|
208
|
+
backoff.max(self.throttle_backoff.next_backoff().unwrap_or_default());
|
|
209
|
+
RetryPolicy::WaitRetry(extended_backoff)
|
|
191
210
|
} else {
|
|
192
211
|
RetryPolicy::WaitRetry(backoff)
|
|
193
212
|
}
|
|
@@ -529,6 +548,16 @@ mod tests {
|
|
|
529
548
|
use std::{ops::Add, time::Instant};
|
|
530
549
|
use tonic::Status;
|
|
531
550
|
|
|
551
|
+
/// Predefined retry configs with low durations to make unit tests faster
|
|
552
|
+
const TEST_RETRY_CONFIG: RetryConfig = RetryConfig {
|
|
553
|
+
initial_interval: Duration::from_millis(1),
|
|
554
|
+
randomization_factor: 0.0,
|
|
555
|
+
multiplier: 1.1,
|
|
556
|
+
max_interval: Duration::from_millis(2),
|
|
557
|
+
max_elapsed_time: None,
|
|
558
|
+
max_retries: 10,
|
|
559
|
+
};
|
|
560
|
+
|
|
532
561
|
#[tokio::test]
|
|
533
562
|
async fn non_retryable_errors() {
|
|
534
563
|
for code in [
|
|
@@ -547,7 +576,7 @@ mod tests {
|
|
|
547
576
|
.expect_cancel_activity_task()
|
|
548
577
|
.returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
|
|
549
578
|
.times(1);
|
|
550
|
-
let retry_client = RetryClient::new(mock_client,
|
|
579
|
+
let retry_client = RetryClient::new(mock_client, TEST_RETRY_CONFIG);
|
|
551
580
|
let result = retry_client
|
|
552
581
|
.cancel_activity_task(vec![1].into(), None)
|
|
553
582
|
.await;
|
|
@@ -575,12 +604,13 @@ mod tests {
|
|
|
575
604
|
Code::Unimplemented,
|
|
576
605
|
] {
|
|
577
606
|
for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
578
|
-
let retry_cfg = RetryConfig::poll_retry_policy();
|
|
579
607
|
let mut err_handler = TonicErrorHandler {
|
|
580
|
-
max_retries:
|
|
608
|
+
max_retries: TEST_RETRY_CONFIG.max_retries,
|
|
581
609
|
call_type: CallType::LongPoll,
|
|
582
610
|
call_name,
|
|
583
|
-
backoff:
|
|
611
|
+
backoff: TEST_RETRY_CONFIG.into_exp_backoff(FixedClock(Instant::now())),
|
|
612
|
+
throttle_backoff: TEST_RETRY_CONFIG
|
|
613
|
+
.into_exp_backoff(FixedClock(Instant::now())),
|
|
584
614
|
};
|
|
585
615
|
let result = err_handler.handle(1, Status::new(code, "Ahh"));
|
|
586
616
|
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
@@ -599,12 +629,13 @@ mod tests {
|
|
|
599
629
|
async fn long_poll_retryable_errors_never_fatal() {
|
|
600
630
|
for code in RETRYABLE_ERROR_CODES {
|
|
601
631
|
for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
602
|
-
let retry_cfg = RetryConfig::poll_retry_policy();
|
|
603
632
|
let mut err_handler = TonicErrorHandler {
|
|
604
|
-
max_retries:
|
|
633
|
+
max_retries: TEST_RETRY_CONFIG.max_retries,
|
|
605
634
|
call_type: CallType::LongPoll,
|
|
606
635
|
call_name,
|
|
607
|
-
backoff:
|
|
636
|
+
backoff: TEST_RETRY_CONFIG.into_exp_backoff(FixedClock(Instant::now())),
|
|
637
|
+
throttle_backoff: TEST_RETRY_CONFIG
|
|
638
|
+
.into_exp_backoff(FixedClock(Instant::now())),
|
|
608
639
|
};
|
|
609
640
|
let result = err_handler.handle(1, Status::new(code, "Ahh"));
|
|
610
641
|
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
@@ -621,7 +652,12 @@ mod tests {
|
|
|
621
652
|
|
|
622
653
|
#[tokio::test]
|
|
623
654
|
async fn retryable_errors() {
|
|
624
|
-
|
|
655
|
+
// Take out retry exhausted since it gets a special policy which would make this take ages
|
|
656
|
+
for code in RETRYABLE_ERROR_CODES
|
|
657
|
+
.iter()
|
|
658
|
+
.copied()
|
|
659
|
+
.filter(|p| p != &Code::ResourceExhausted)
|
|
660
|
+
{
|
|
625
661
|
let mut mock_client = MockWorkflowClientTrait::new();
|
|
626
662
|
mock_client
|
|
627
663
|
.expect_cancel_activity_task()
|
|
@@ -632,7 +668,7 @@ mod tests {
|
|
|
632
668
|
.returning(|_, _| Ok(Default::default()))
|
|
633
669
|
.times(1);
|
|
634
670
|
|
|
635
|
-
let retry_client = RetryClient::new(mock_client,
|
|
671
|
+
let retry_client = RetryClient::new(mock_client, TEST_RETRY_CONFIG);
|
|
636
672
|
let result = retry_client
|
|
637
673
|
.cancel_activity_task(vec![1].into(), None)
|
|
638
674
|
.await;
|
|
@@ -641,15 +677,53 @@ mod tests {
|
|
|
641
677
|
}
|
|
642
678
|
}
|
|
643
679
|
|
|
680
|
+
#[tokio::test]
|
|
681
|
+
async fn retry_resource_exhausted() {
|
|
682
|
+
let mut err_handler = TonicErrorHandler {
|
|
683
|
+
max_retries: TEST_RETRY_CONFIG.max_retries,
|
|
684
|
+
call_type: CallType::Normal,
|
|
685
|
+
call_name: POLL_WORKFLOW_METH_NAME,
|
|
686
|
+
backoff: TEST_RETRY_CONFIG.into_exp_backoff(FixedClock(Instant::now())),
|
|
687
|
+
throttle_backoff: RetryConfig {
|
|
688
|
+
initial_interval: Duration::from_millis(2),
|
|
689
|
+
randomization_factor: 0.0,
|
|
690
|
+
multiplier: 4.0,
|
|
691
|
+
max_interval: Duration::from_millis(10),
|
|
692
|
+
max_elapsed_time: None,
|
|
693
|
+
max_retries: 10,
|
|
694
|
+
}
|
|
695
|
+
.into_exp_backoff(FixedClock(Instant::now())),
|
|
696
|
+
};
|
|
697
|
+
let result = err_handler.handle(1, Status::new(Code::ResourceExhausted, "leave me alone"));
|
|
698
|
+
match result {
|
|
699
|
+
RetryPolicy::WaitRetry(duration) => assert_eq!(duration, Duration::from_millis(2)),
|
|
700
|
+
_ => panic!(),
|
|
701
|
+
}
|
|
702
|
+
err_handler.backoff.clock.0 = err_handler.backoff.clock.0.add(Duration::from_millis(10));
|
|
703
|
+
err_handler.throttle_backoff.clock.0 = err_handler
|
|
704
|
+
.throttle_backoff
|
|
705
|
+
.clock
|
|
706
|
+
.0
|
|
707
|
+
.add(Duration::from_millis(10));
|
|
708
|
+
let result = err_handler.handle(2, Status::new(Code::ResourceExhausted, "leave me alone"));
|
|
709
|
+
match result {
|
|
710
|
+
RetryPolicy::WaitRetry(duration) => assert_eq!(duration, Duration::from_millis(8)),
|
|
711
|
+
_ => panic!(),
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
644
715
|
#[tokio::test]
|
|
645
716
|
async fn long_poll_retries_forever() {
|
|
646
717
|
// A bit odd, but we don't need a real client to test the retry client passes through the
|
|
647
718
|
// correct retry config
|
|
648
|
-
let fake_retry = RetryClient::new((),
|
|
719
|
+
let fake_retry = RetryClient::new((), TEST_RETRY_CONFIG);
|
|
649
720
|
for i in 1..=50 {
|
|
650
721
|
for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
651
|
-
let mut err_handler =
|
|
652
|
-
|
|
722
|
+
let mut err_handler = TonicErrorHandler::new(
|
|
723
|
+
fake_retry.get_retry_config(call),
|
|
724
|
+
fake_retry.get_retry_config(call),
|
|
725
|
+
call,
|
|
726
|
+
);
|
|
653
727
|
let result = err_handler.handle(i, Status::new(Code::Unknown, "Ahh"));
|
|
654
728
|
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
655
729
|
}
|
|
@@ -658,12 +732,15 @@ mod tests {
|
|
|
658
732
|
|
|
659
733
|
#[tokio::test]
|
|
660
734
|
async fn long_poll_retries_deadline_exceeded() {
|
|
661
|
-
let fake_retry = RetryClient::new((),
|
|
735
|
+
let fake_retry = RetryClient::new((), TEST_RETRY_CONFIG);
|
|
662
736
|
// For some reason we will get cancelled in these situations occasionally (always?) too
|
|
663
737
|
for code in [Code::Cancelled, Code::DeadlineExceeded] {
|
|
664
738
|
for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
665
|
-
let mut err_handler =
|
|
666
|
-
|
|
739
|
+
let mut err_handler = TonicErrorHandler::new(
|
|
740
|
+
fake_retry.get_retry_config(call),
|
|
741
|
+
fake_retry.get_retry_config(call),
|
|
742
|
+
call,
|
|
743
|
+
);
|
|
667
744
|
for i in 1..=5 {
|
|
668
745
|
let result = err_handler.handle(i, Status::new(code, "retryable failure"));
|
|
669
746
|
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
package/sdk-core/core/Cargo.toml
CHANGED
|
@@ -20,7 +20,7 @@ async-trait = "0.1"
|
|
|
20
20
|
base64 = "0.13"
|
|
21
21
|
crossbeam = "0.8"
|
|
22
22
|
dashmap = "5.0"
|
|
23
|
-
derive_builder = "0.
|
|
23
|
+
derive_builder = "0.12"
|
|
24
24
|
derive_more = "0.99"
|
|
25
25
|
enum_dispatch = "0.3"
|
|
26
26
|
flate2 = "1.0"
|
|
@@ -34,7 +34,7 @@ lazy_static = "1.4"
|
|
|
34
34
|
log = "0.4"
|
|
35
35
|
lru = "0.8"
|
|
36
36
|
mockall = "0.11"
|
|
37
|
-
nix = "0.
|
|
37
|
+
nix = "0.26"
|
|
38
38
|
once_cell = "1.5"
|
|
39
39
|
opentelemetry = { version = "0.18", features = ["rt-tokio"] }
|
|
40
40
|
opentelemetry-otlp = { version = "0.11", features = ["tokio", "metrics"] }
|
|
@@ -45,7 +45,7 @@ prost = "0.11"
|
|
|
45
45
|
prost-types = "0.11"
|
|
46
46
|
rand = "0.8.3"
|
|
47
47
|
reqwest = { version = "0.11", features = ["json", "stream", "rustls-tls", "tokio-rustls"], default-features = false }
|
|
48
|
-
ringbuf = "0.
|
|
48
|
+
ringbuf = "0.3"
|
|
49
49
|
serde = "1.0"
|
|
50
50
|
serde_json = "1.0"
|
|
51
51
|
siphasher = "0.3"
|
|
@@ -59,7 +59,7 @@ tonic = { version = "0.8", features = ["tls", "tls-roots"] }
|
|
|
59
59
|
tracing = { version = "0.1", features = ["log-always"] }
|
|
60
60
|
tracing-futures = "0.2"
|
|
61
61
|
tracing-opentelemetry = "0.18"
|
|
62
|
-
tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter"] }
|
|
62
|
+
tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter", "registry"] }
|
|
63
63
|
url = "2.2"
|
|
64
64
|
uuid = { version = "1.1", features = ["v4"] }
|
|
65
65
|
zip = "0.6"
|
|
@@ -86,7 +86,7 @@ version = "0.1"
|
|
|
86
86
|
assert_matches = "1.4"
|
|
87
87
|
bimap = "0.6.1"
|
|
88
88
|
criterion = "0.4"
|
|
89
|
-
rstest = "0.
|
|
89
|
+
rstest = "0.16"
|
|
90
90
|
temporal-sdk-core-test-utils = { path = "../test-utils" }
|
|
91
91
|
temporal-sdk = { path = "../sdk" }
|
|
92
92
|
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
use criterion::{criterion_group, criterion_main, Criterion};
|
|
2
2
|
use futures::StreamExt;
|
|
3
3
|
use std::time::Duration;
|
|
4
|
-
use temporal_sdk::{WfContext,
|
|
5
|
-
use temporal_sdk_core::
|
|
4
|
+
use temporal_sdk::{WfContext, WorkflowFunction};
|
|
5
|
+
use temporal_sdk_core::replay::HistoryForReplay;
|
|
6
6
|
use temporal_sdk_core_protos::DEFAULT_WORKFLOW_TYPE;
|
|
7
|
-
use temporal_sdk_core_test_utils::{canned_histories,
|
|
7
|
+
use temporal_sdk_core_test_utils::{canned_histories, replay_sdk_worker};
|
|
8
8
|
|
|
9
9
|
pub fn criterion_benchmark(c: &mut Criterion) {
|
|
10
10
|
let tokio_runtime = tokio::runtime::Builder::new_current_thread()
|
|
11
11
|
.enable_time()
|
|
12
12
|
.build()
|
|
13
13
|
.unwrap();
|
|
14
|
-
telemetry_init(&TelemetryOptionsBuilder::default().build().unwrap()).unwrap();
|
|
15
14
|
let _g = tokio_runtime.enter();
|
|
16
15
|
|
|
17
16
|
let num_timers = 10;
|
|
18
17
|
let t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
19
|
-
let hist =
|
|
18
|
+
let hist = HistoryForReplay::new(
|
|
19
|
+
t.get_full_history_info().unwrap().into(),
|
|
20
|
+
"whatever".to_string(),
|
|
21
|
+
);
|
|
20
22
|
|
|
21
23
|
c.bench_function("Small history replay", |b| {
|
|
22
24
|
b.iter(|| {
|
|
23
25
|
tokio_runtime.block_on(async {
|
|
24
26
|
let func = timers_wf(num_timers);
|
|
25
|
-
let
|
|
26
|
-
let mut worker = Worker::new_from_core(worker, "replay_bench".to_string());
|
|
27
|
+
let mut worker = replay_sdk_worker([hist.clone()]);
|
|
27
28
|
worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
|
|
28
29
|
worker.run().await.unwrap();
|
|
29
30
|
})
|
|
@@ -32,14 +33,16 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|
|
32
33
|
|
|
33
34
|
let num_tasks = 50;
|
|
34
35
|
let t = canned_histories::lots_of_big_signals(num_tasks);
|
|
35
|
-
let hist =
|
|
36
|
+
let hist = HistoryForReplay::new(
|
|
37
|
+
t.get_full_history_info().unwrap().into(),
|
|
38
|
+
"whatever".to_string(),
|
|
39
|
+
);
|
|
36
40
|
|
|
37
41
|
c.bench_function("Large payloads history replay", |b| {
|
|
38
42
|
b.iter(|| {
|
|
39
43
|
tokio_runtime.block_on(async {
|
|
40
44
|
let func = big_signals_wf(num_tasks);
|
|
41
|
-
let
|
|
42
|
-
let mut worker = Worker::new_from_core(worker, "large_hist_bench".to_string());
|
|
45
|
+
let mut worker = replay_sdk_worker([hist.clone()]);
|
|
43
46
|
worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
|
|
44
47
|
worker.run().await.unwrap();
|
|
45
48
|
})
|
|
@@ -4,10 +4,9 @@ use crate::MetricsContext;
|
|
|
4
4
|
use futures::{stream, Stream, StreamExt};
|
|
5
5
|
use std::{
|
|
6
6
|
fmt::{Debug, Formatter},
|
|
7
|
-
future::Future,
|
|
8
7
|
sync::Arc,
|
|
9
8
|
};
|
|
10
|
-
use tokio::sync::{AcquireError,
|
|
9
|
+
use tokio::sync::{AcquireError, OwnedSemaphorePermit, Semaphore, TryAcquireError};
|
|
11
10
|
|
|
12
11
|
/// Wraps a [Semaphore] with a function call that is fed the available permits any time a permit is
|
|
13
12
|
/// acquired or restored through the provided methods
|
|
@@ -82,24 +81,29 @@ impl Debug for OwnedMeteredSemPermit {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
/// From the input stream, create a new stream which only pulls from the input stream when allowed.
|
|
85
|
-
/// When allowed is determined by the passed in `proceeder`
|
|
86
|
-
///
|
|
87
|
-
|
|
84
|
+
/// When allowed is determined by the passed in `proceeder` emitting an item. The input stream is
|
|
85
|
+
/// only pulled from when that future resolves.
|
|
86
|
+
///
|
|
87
|
+
/// This is *almost* identical to `zip`, but does not terminate early if the input stream closes.
|
|
88
|
+
/// The proceeder must allow the poll before the returned stream closes. If the proceeder terminates
|
|
89
|
+
/// the overall stream will terminate.
|
|
90
|
+
pub(crate) fn stream_when_allowed<S, AS>(
|
|
88
91
|
input: S,
|
|
89
|
-
proceeder:
|
|
90
|
-
) -> impl Stream<Item = (S::Item,
|
|
92
|
+
proceeder: AS,
|
|
93
|
+
) -> impl Stream<Item = (S::Item, AS::Item)>
|
|
91
94
|
where
|
|
92
95
|
S: Stream + Send + 'static,
|
|
93
|
-
|
|
94
|
-
FF: FnMut() -> F,
|
|
96
|
+
AS: Stream + Send + 'static,
|
|
95
97
|
{
|
|
96
|
-
let acceptable_notify = Arc::new(Notify::new());
|
|
97
|
-
acceptable_notify.notify_one();
|
|
98
98
|
let stream = stream::unfold(
|
|
99
|
-
(proceeder, input.boxed()),
|
|
99
|
+
(proceeder.boxed(), input.boxed()),
|
|
100
100
|
|(mut proceeder, mut input)| async {
|
|
101
|
-
let v = proceeder().await;
|
|
102
|
-
|
|
101
|
+
let v = proceeder.next().await;
|
|
102
|
+
if let Some(v) = v {
|
|
103
|
+
input.next().await.map(|i| ((i, v), (proceeder, input)))
|
|
104
|
+
} else {
|
|
105
|
+
None
|
|
106
|
+
}
|
|
103
107
|
},
|
|
104
108
|
);
|
|
105
109
|
stream
|
|
@@ -108,7 +112,7 @@ where
|
|
|
108
112
|
macro_rules! dbg_panic {
|
|
109
113
|
($($arg:tt)*) => {
|
|
110
114
|
error!($($arg)*);
|
|
111
|
-
debug_assert!(
|
|
115
|
+
debug_assert!(false, $($arg)*);
|
|
112
116
|
};
|
|
113
117
|
}
|
|
114
118
|
pub(crate) use dbg_panic;
|
|
@@ -117,19 +121,15 @@ pub(crate) use dbg_panic;
|
|
|
117
121
|
mod tests {
|
|
118
122
|
use super::*;
|
|
119
123
|
use futures::pin_mut;
|
|
120
|
-
use std::
|
|
124
|
+
use std::task::Poll;
|
|
121
125
|
use tokio::sync::mpsc::unbounded_channel;
|
|
126
|
+
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
122
127
|
|
|
123
|
-
// This is fine. Test only / guaranteed to happen serially.
|
|
124
|
-
#[allow(clippy::await_holding_refcell_ref)]
|
|
125
128
|
#[test]
|
|
126
129
|
fn stream_when_allowed_works() {
|
|
127
130
|
let inputs = stream::iter([1, 2, 3]);
|
|
128
131
|
let (allow_tx, allow_rx) = unbounded_channel();
|
|
129
|
-
let
|
|
130
|
-
let when_allowed = stream_when_allowed(inputs, || async {
|
|
131
|
-
allow_rx.borrow_mut().recv().await.unwrap()
|
|
132
|
-
});
|
|
132
|
+
let when_allowed = stream_when_allowed(inputs, UnboundedReceiverStream::new(allow_rx));
|
|
133
133
|
|
|
134
134
|
let waker = futures::task::noop_waker_ref();
|
|
135
135
|
let mut cx = std::task::Context::from_waker(waker);
|
|
@@ -438,7 +438,7 @@ async fn many_concurrent_heartbeat_cancels() {
|
|
|
438
438
|
#[tokio::test]
|
|
439
439
|
async fn activity_timeout_no_double_resolve() {
|
|
440
440
|
let t = canned_histories::activity_double_resolve_repro();
|
|
441
|
-
let core = build_fake_worker("fake_wf_id", t,
|
|
441
|
+
let core = build_fake_worker("fake_wf_id", t, [3]);
|
|
442
442
|
let activity_id = 1;
|
|
443
443
|
|
|
444
444
|
poll_and_reply(
|