chalk-remote-call-python 1.10.1__tar.gz → 1.10.2__tar.gz
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.
- {chalk_remote_call_python-1.10.1/chalk_remote_call_python.egg-info → chalk_remote_call_python-1.10.2}/PKG-INFO +1 -1
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/Cargo.lock +1 -1
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/Cargo.toml +1 -1
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/self_consumer.rs +192 -19
- chalk_remote_call_python-1.10.2/chalk_remote_call/_version.py +1 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2/chalk_remote_call_python.egg-info}/PKG-INFO +1 -1
- chalk_remote_call_python-1.10.1/chalk_remote_call/_version.py +0 -1
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/MANIFEST.in +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/README.md +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/Cargo.toml +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/Cargo.toml +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.auth.v1.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.common.v1.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.tonic.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.utils.v1.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/descriptor.bin +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/lib.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/async_service.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/coalesce.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/lib.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/metrics.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/python_bridge.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/server.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/chalk-remote-call-server/src/service.rs +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/rust-toolchain.toml +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/__main__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/auth/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/auth/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/common/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/common/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/runtime/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/runtime/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_native.pyi +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/arrow_utils.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/cli.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/errors.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/handler_loader.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/input_transform.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/logging.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/server.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/servicer.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/tracing.py +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call_python.egg-info/SOURCES.txt +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call_python.egg-info/dependency_links.txt +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call_python.egg-info/entry_points.txt +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call_python.egg-info/requires.txt +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call_python.egg-info/top_level.txt +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/pyproject.toml +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/setup.cfg +0 -0
- {chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/setup.py +0 -0
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/Cargo.lock
RENAMED
|
@@ -511,7 +511,7 @@ dependencies = [
|
|
|
511
511
|
[[package]]
|
|
512
512
|
name = "chalk-queue"
|
|
513
513
|
version = "0.0.0"
|
|
514
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
514
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=1460144ea659debbaee9dccadcd4d7dbf383ccf8#1460144ea659debbaee9dccadcd4d7dbf383ccf8"
|
|
515
515
|
dependencies = [
|
|
516
516
|
"base64 0.22.1",
|
|
517
517
|
"redis",
|
|
@@ -37,6 +37,6 @@ futures-util = "0.3"
|
|
|
37
37
|
# `[patch.crates-io]` here it builds against vanilla crates.io redis (it only
|
|
38
38
|
# uses standard APIs). Metrics and StatsD share a revision so their client types agree.
|
|
39
39
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
40
|
-
chalk-queue = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "
|
|
40
|
+
chalk-queue = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "1460144ea659debbaee9dccadcd4d7dbf383ccf8" }
|
|
41
41
|
chalk_metrics = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "a0f8932ec10d3b8340af3e98cf63b800d60b4926" }
|
|
42
42
|
chalk_statsd = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "a0f8932ec10d3b8340af3e98cf63b800d60b4926" }
|
|
@@ -39,7 +39,7 @@ use std::time::{Duration, Instant};
|
|
|
39
39
|
|
|
40
40
|
use chalk_queue::semaphore::renew_many;
|
|
41
41
|
use chalk_queue::stream_writer;
|
|
42
|
-
use chalk_queue::types::QueuedCall;
|
|
42
|
+
use chalk_queue::types::{DeliveryAttempt, QueuedCall};
|
|
43
43
|
use chalk_queue::{
|
|
44
44
|
BoundFunctionQueue, DequeuedCall, FunctionQueue, QueueProtocol, QueueReceipt, SemaphoreLease,
|
|
45
45
|
};
|
|
@@ -689,23 +689,81 @@ async fn run_one_call(
|
|
|
689
689
|
flush_timeout: Duration,
|
|
690
690
|
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
691
691
|
) {
|
|
692
|
+
let attempt = match input_queue.delivery_attempt(&delivery).await {
|
|
693
|
+
Ok(attempt) => attempt,
|
|
694
|
+
Err(error) => {
|
|
695
|
+
error!(call_id = %delivery.call.call_id, %error, "failed to resolve delivery attempt");
|
|
696
|
+
finish_delivery(
|
|
697
|
+
&input_queue,
|
|
698
|
+
&delivery.receipt,
|
|
699
|
+
false,
|
|
700
|
+
&delivery.call.call_id,
|
|
701
|
+
lease,
|
|
702
|
+
&live_calls,
|
|
703
|
+
)
|
|
704
|
+
.await;
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
};
|
|
692
708
|
let DequeuedCall {
|
|
693
709
|
call: work,
|
|
694
710
|
receipt,
|
|
695
711
|
} = delivery;
|
|
696
712
|
let call_id = work.call_id.clone();
|
|
713
|
+
let final_attempt = match attempt {
|
|
714
|
+
DeliveryAttempt::Ready {
|
|
715
|
+
attempt,
|
|
716
|
+
max_attempts,
|
|
717
|
+
} => {
|
|
718
|
+
info!(%call_id, attempt, max_attempts, "executing queued call attempt");
|
|
719
|
+
attempt == max_attempts
|
|
720
|
+
}
|
|
721
|
+
DeliveryAttempt::Exhausted {
|
|
722
|
+
attempts,
|
|
723
|
+
max_attempts,
|
|
724
|
+
} => {
|
|
725
|
+
let message = format!(
|
|
726
|
+
"retry attempts exhausted after {attempts} deliveries ({max_attempts} executions allowed)"
|
|
727
|
+
);
|
|
728
|
+
let completed = write_terminal_error(
|
|
729
|
+
&queue,
|
|
730
|
+
&mut conn,
|
|
731
|
+
&work,
|
|
732
|
+
"RetryAttemptsExhausted",
|
|
733
|
+
&message,
|
|
734
|
+
None,
|
|
735
|
+
)
|
|
736
|
+
.await
|
|
737
|
+
.is_ok();
|
|
738
|
+
finish_delivery(
|
|
739
|
+
&input_queue,
|
|
740
|
+
&receipt,
|
|
741
|
+
completed,
|
|
742
|
+
&call_id,
|
|
743
|
+
lease,
|
|
744
|
+
&live_calls,
|
|
745
|
+
)
|
|
746
|
+
.await;
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
DeliveryAttempt::OwnershipLost => {
|
|
750
|
+
finish_delivery(&input_queue, &receipt, false, &call_id, lease, &live_calls).await;
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
};
|
|
697
754
|
let completed = match AssertUnwindSafe(execute_and_write(
|
|
698
755
|
&handler,
|
|
699
756
|
&queue,
|
|
700
757
|
&mut conn,
|
|
701
|
-
work,
|
|
758
|
+
work.clone(),
|
|
702
759
|
flush_timeout,
|
|
760
|
+
final_attempt,
|
|
703
761
|
metrics_pipeline.as_ref(),
|
|
704
762
|
))
|
|
705
763
|
.catch_unwind()
|
|
706
764
|
.await
|
|
707
765
|
{
|
|
708
|
-
Ok(Ok(
|
|
766
|
+
Ok(Ok(completed)) => completed,
|
|
709
767
|
Ok(Err(e)) => {
|
|
710
768
|
// The call's result stream may be incomplete; the enqueue safety TTL
|
|
711
769
|
// and the meta status are the backstop for a stuck poller.
|
|
@@ -723,7 +781,20 @@ async fn run_one_call(
|
|
|
723
781
|
panic = %panic_message,
|
|
724
782
|
"panic while executing/writing queued call"
|
|
725
783
|
);
|
|
726
|
-
|
|
784
|
+
if final_attempt {
|
|
785
|
+
write_terminal_error(
|
|
786
|
+
&queue,
|
|
787
|
+
&mut conn,
|
|
788
|
+
&work,
|
|
789
|
+
"RemoteFunctionPanic",
|
|
790
|
+
panic_message,
|
|
791
|
+
None,
|
|
792
|
+
)
|
|
793
|
+
.await
|
|
794
|
+
.is_ok()
|
|
795
|
+
} else {
|
|
796
|
+
false
|
|
797
|
+
}
|
|
727
798
|
}
|
|
728
799
|
};
|
|
729
800
|
|
|
@@ -777,21 +848,79 @@ async fn run_one_coalesced_call(
|
|
|
777
848
|
live_calls: LiveCalls,
|
|
778
849
|
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
779
850
|
) {
|
|
851
|
+
let attempt = match input_queue.delivery_attempt(&delivery).await {
|
|
852
|
+
Ok(attempt) => attempt,
|
|
853
|
+
Err(error) => {
|
|
854
|
+
error!(call_id = %delivery.call.call_id, %error, "failed to resolve delivery attempt");
|
|
855
|
+
finish_delivery(
|
|
856
|
+
&input_queue,
|
|
857
|
+
&delivery.receipt,
|
|
858
|
+
false,
|
|
859
|
+
&delivery.call.call_id,
|
|
860
|
+
lease,
|
|
861
|
+
&live_calls,
|
|
862
|
+
)
|
|
863
|
+
.await;
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
};
|
|
780
867
|
let DequeuedCall {
|
|
781
868
|
call: work,
|
|
782
869
|
receipt,
|
|
783
870
|
} = delivery;
|
|
784
871
|
let call_id = work.call_id.clone();
|
|
872
|
+
let final_attempt = match attempt {
|
|
873
|
+
DeliveryAttempt::Ready {
|
|
874
|
+
attempt,
|
|
875
|
+
max_attempts,
|
|
876
|
+
} => {
|
|
877
|
+
info!(%call_id, attempt, max_attempts, "executing coalesced queued call attempt");
|
|
878
|
+
attempt == max_attempts
|
|
879
|
+
}
|
|
880
|
+
DeliveryAttempt::Exhausted {
|
|
881
|
+
attempts,
|
|
882
|
+
max_attempts,
|
|
883
|
+
} => {
|
|
884
|
+
let message = format!(
|
|
885
|
+
"retry attempts exhausted after {attempts} deliveries ({max_attempts} executions allowed)"
|
|
886
|
+
);
|
|
887
|
+
let completed = write_terminal_error(
|
|
888
|
+
&queue,
|
|
889
|
+
&mut conn,
|
|
890
|
+
&work,
|
|
891
|
+
"RetryAttemptsExhausted",
|
|
892
|
+
&message,
|
|
893
|
+
None,
|
|
894
|
+
)
|
|
895
|
+
.await
|
|
896
|
+
.is_ok();
|
|
897
|
+
finish_delivery(
|
|
898
|
+
&input_queue,
|
|
899
|
+
&receipt,
|
|
900
|
+
completed,
|
|
901
|
+
&call_id,
|
|
902
|
+
lease,
|
|
903
|
+
&live_calls,
|
|
904
|
+
)
|
|
905
|
+
.await;
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
DeliveryAttempt::OwnershipLost => {
|
|
909
|
+
finish_delivery(&input_queue, &receipt, false, &call_id, lease, &live_calls).await;
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
};
|
|
785
913
|
let completed = match coalesced_execute_and_write(
|
|
786
914
|
&coalescing_queue,
|
|
787
915
|
&queue,
|
|
788
916
|
&mut conn,
|
|
789
917
|
work,
|
|
918
|
+
final_attempt,
|
|
790
919
|
metrics_pipeline.as_ref(),
|
|
791
920
|
)
|
|
792
921
|
.await
|
|
793
922
|
{
|
|
794
|
-
Ok(
|
|
923
|
+
Ok(completed) => completed,
|
|
795
924
|
Err(e) => {
|
|
796
925
|
// The call's result stream may be incomplete; the enqueue safety TTL
|
|
797
926
|
// and the meta status are the backstop for a stuck poller.
|
|
@@ -821,8 +950,9 @@ async fn coalesced_execute_and_write(
|
|
|
821
950
|
queue: &FunctionQueue,
|
|
822
951
|
conn: &mut ConnectionManager,
|
|
823
952
|
work: QueuedCall,
|
|
953
|
+
final_attempt: bool,
|
|
824
954
|
metrics_pipeline: Option<&Arc<PublishingMetricsPipeline>>,
|
|
825
|
-
) -> Result<
|
|
955
|
+
) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
|
|
826
956
|
let call_uuid = Uuid::parse_str(&work.call_id)?;
|
|
827
957
|
let result_destination = ResultDestination::for_call(queue, &work, call_uuid);
|
|
828
958
|
let ipc_bytes = work.call.feather_bytes()?;
|
|
@@ -881,6 +1011,10 @@ async fn coalesced_execute_and_write(
|
|
|
881
1011
|
info!(call_id = %work.call_id, "coalesced queued call completed");
|
|
882
1012
|
}
|
|
883
1013
|
Some(Err(status)) => {
|
|
1014
|
+
if !final_attempt {
|
|
1015
|
+
warn!(call_id = %work.call_id, error = %status, "coalesced queued call failed; leaving delivery pending for retry");
|
|
1016
|
+
return Ok(false);
|
|
1017
|
+
}
|
|
884
1018
|
// Parity with the enqueue/poll path: only a message string is
|
|
885
1019
|
// available, so exc_type is a fixed placeholder.
|
|
886
1020
|
result_destination
|
|
@@ -897,6 +1031,10 @@ async fn coalesced_execute_and_write(
|
|
|
897
1031
|
// happen (it always sends one Ok/Err per caller), but treat a
|
|
898
1032
|
// missing response as a failure rather than leaving the poller hung.
|
|
899
1033
|
let msg = "coalesced dispatch produced no response";
|
|
1034
|
+
if !final_attempt {
|
|
1035
|
+
warn!(call_id = %work.call_id, "{msg}; leaving delivery pending for retry");
|
|
1036
|
+
return Ok(false);
|
|
1037
|
+
}
|
|
900
1038
|
result_destination
|
|
901
1039
|
.write_error(conn, 1, "RemoteFunctionError", msg, None)
|
|
902
1040
|
.await?;
|
|
@@ -906,7 +1044,7 @@ async fn coalesced_execute_and_write(
|
|
|
906
1044
|
error!(call_id = %work.call_id, "{msg}");
|
|
907
1045
|
}
|
|
908
1046
|
}
|
|
909
|
-
Ok(
|
|
1047
|
+
Ok(true)
|
|
910
1048
|
}
|
|
911
1049
|
|
|
912
1050
|
// Insert trace ID into headers if none already present
|
|
@@ -934,8 +1072,9 @@ async fn execute_and_write(
|
|
|
934
1072
|
conn: &mut ConnectionManager,
|
|
935
1073
|
work: QueuedCall,
|
|
936
1074
|
flush_timeout: Duration,
|
|
1075
|
+
final_attempt: bool,
|
|
937
1076
|
metrics_pipeline: Option<&Arc<PublishingMetricsPipeline>>,
|
|
938
|
-
) -> Result<
|
|
1077
|
+
) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
|
|
939
1078
|
let call_uuid = Uuid::parse_str(&work.call_id)?;
|
|
940
1079
|
let result_destination = ResultDestination::for_call(queue, &work, call_uuid);
|
|
941
1080
|
let ipc_bytes = work.call.feather_bytes()?;
|
|
@@ -947,13 +1086,9 @@ async fn execute_and_write(
|
|
|
947
1086
|
let _ = queue.update_status(call_uuid, "running").await;
|
|
948
1087
|
info!(call_id = %work.call_id, function = %function_name, "running queued call");
|
|
949
1088
|
|
|
950
|
-
// The
|
|
951
|
-
//
|
|
952
|
-
//
|
|
953
|
-
// handler returns: we wait on the notify (signaled on each append) and flush
|
|
954
|
-
// immediately when chunks arrive, so a slow generator's early yields reach
|
|
955
|
-
// the client without waiting for the whole call to finish. A timeout fallback
|
|
956
|
-
// ensures we make progress if the notification pipeline breaks.
|
|
1089
|
+
// The Python bridge appends each generator yield into `buffer`. Calls
|
|
1090
|
+
// without retries flush incrementally; retry-enabled calls retain chunks
|
|
1091
|
+
// until the attempt succeeds so a later attempt cannot duplicate output.
|
|
957
1092
|
let buffer = ChunkBuffer::new().into_shared();
|
|
958
1093
|
let handler_fut = handler.call_into_buffer(
|
|
959
1094
|
ipc_bytes,
|
|
@@ -968,6 +1103,9 @@ async fn execute_and_write(
|
|
|
968
1103
|
// seq 0. `flushed` is the count of chunks already written to the stream.
|
|
969
1104
|
let mut seq: u64 = 1;
|
|
970
1105
|
let mut flushed: usize = 0;
|
|
1106
|
+
// A retry must not duplicate generator chunks. Retry-enabled calls buffer
|
|
1107
|
+
// output until the handler succeeds or reaches its final attempt.
|
|
1108
|
+
let buffer_until_terminal = work.max_retries.is_some();
|
|
971
1109
|
|
|
972
1110
|
// Completion is driven by the handler future resolving, NOT by the buffer
|
|
973
1111
|
// emitter being torn down — so a handler that pins its emitter (e.g. via a
|
|
@@ -984,10 +1122,12 @@ async fn execute_and_write(
|
|
|
984
1122
|
biased;
|
|
985
1123
|
res = &mut handler_fut => break res,
|
|
986
1124
|
_ = tokio::time::timeout(flush_timeout, notify_handle.notified()) => {
|
|
987
|
-
if
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1125
|
+
if !buffer_until_terminal {
|
|
1126
|
+
if let Err(e) = flush_new(conn, &result_destination, &buffer, &mut flushed, &mut seq).await {
|
|
1127
|
+
// Non-fatal: keep draining; the cursor didn't advance past the
|
|
1128
|
+
// failed chunk, so the next wait retries it without duplicating.
|
|
1129
|
+
warn!(call_id = %work.call_id, error = %e, "failed to flush partial results; retrying");
|
|
1130
|
+
}
|
|
991
1131
|
}
|
|
992
1132
|
}
|
|
993
1133
|
}
|
|
@@ -1006,6 +1146,11 @@ async fn execute_and_write(
|
|
|
1006
1146
|
);
|
|
1007
1147
|
}
|
|
1008
1148
|
|
|
1149
|
+
if result.is_err() && !final_attempt {
|
|
1150
|
+
warn!(call_id = %work.call_id, "queued call failed; leaving delivery pending for retry");
|
|
1151
|
+
return Ok(false);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1009
1154
|
// Flush whatever the handler produced after the loop exits (on the fast path
|
|
1010
1155
|
// this is everything). This happens even if the handler panicked mid-execution,
|
|
1011
1156
|
// so partial output is always preserved. Parity with the enqueue/poll path: a
|
|
@@ -1049,6 +1194,34 @@ async fn execute_and_write(
|
|
|
1049
1194
|
);
|
|
1050
1195
|
}
|
|
1051
1196
|
}
|
|
1197
|
+
Ok(true)
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
async fn write_terminal_error(
|
|
1201
|
+
queue: &FunctionQueue,
|
|
1202
|
+
conn: &mut ConnectionManager,
|
|
1203
|
+
work: &QueuedCall,
|
|
1204
|
+
exc_type: &str,
|
|
1205
|
+
message: &str,
|
|
1206
|
+
traceback: Option<&str>,
|
|
1207
|
+
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
1208
|
+
let call_uuid = Uuid::parse_str(&work.call_id)?;
|
|
1209
|
+
let result_destination = ResultDestination::for_call(queue, work, call_uuid);
|
|
1210
|
+
result_destination
|
|
1211
|
+
.write_error(conn, 1, exc_type, message, traceback)
|
|
1212
|
+
.await?;
|
|
1213
|
+
let summary: String = message.chars().take(200).collect();
|
|
1214
|
+
let processing_trace_id = work
|
|
1215
|
+
.metadata
|
|
1216
|
+
.otel_headers
|
|
1217
|
+
.get("traceparent")
|
|
1218
|
+
.and_then(|value| value.split('-').nth(1))
|
|
1219
|
+
.filter(|value| value.len() == 32)
|
|
1220
|
+
.map(str::to_string);
|
|
1221
|
+
let _ = queue
|
|
1222
|
+
.complete_status(call_uuid, "failed", &summary, processing_trace_id)
|
|
1223
|
+
.await;
|
|
1224
|
+
error!(call_id = %work.call_id, %message, "queued call reached terminal failure");
|
|
1052
1225
|
Ok(())
|
|
1053
1226
|
}
|
|
1054
1227
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.10.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.10.1"
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk-remote-call-rs/Cargo.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/__init__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/_native.pyi
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/arrow_utils.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/cli.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/logging.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/server.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/servicer.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.10.1 → chalk_remote_call_python-1.10.2}/chalk_remote_call/tracing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|