fix(managed): decouple peer-close control from event delivery
Add a scheduler-owned saturating peer-close counter shared with the group session. Update it before best-effort TargetFinished publication so bounded subscriber overflow cannot hide the live shutdown condition, while retaining the existing events, bounded history, and aggregate accounting. Make grouped CLI and TUI supervision consult the durable count on each existing activity loop and funnel both count and event observations through one-shot stop policy. Preserve interruption suppression, queued-event draining, structured failures, drop reporting, and peer-close diagnostic precedence. Cover scheduler-only accounting, non-peer exclusions, receiver and removal races, deterministic capacity-one DropOldest eviction with an active target, frontend one-shot policy, and the existing process-level peer-close and interruption behavior.
This commit is contained in:
1 parent
bbe3261eb3
commit
7cc55bd619
4 files changed
+316
-59
No files matched your search
@@ -26,8 +26,8 @@ use crate::shared::client::expected_probe_count;
|
||||
use crate::shared::client::{
|
||||
is_shutdown_requested,
|
||||
session::{
|
||||
peer_close_run_error, request_group_stop_once, should_print_final_summary,
|
||||
should_stop_group_on_peer_close,
|
||||
peer_close_run_error, request_group_stop_for_peer_close, request_group_stop_once,
|
||||
should_print_final_summary,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -396,6 +396,15 @@ fn run_group_stream(
|
||||
session.stop();
|
||||
}
|
||||
}
|
||||
if request_group_stop_for_peer_close(
|
||||
continuous,
|
||||
interrupted,
|
||||
session.peer_closed_target_count(),
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
) {
|
||||
session.stop();
|
||||
}
|
||||
|
||||
match events.try_recv() {
|
||||
Ok(Some(group_event)) => {
|
||||
@@ -423,15 +432,17 @@ fn run_group_stream(
|
||||
ManagedGroupEvent::TargetFinished(target) => {
|
||||
report_target_failure(&target);
|
||||
terminal_targets.insert(target.id.as_str().to_owned());
|
||||
if should_stop_group_on_peer_close(
|
||||
if request_group_stop_for_peer_close(
|
||||
continuous,
|
||||
interrupted,
|
||||
&target.end_reason,
|
||||
u64::from(matches!(
|
||||
&target.end_reason,
|
||||
irtt_client::ManagedTargetEndReason::PeerClosed
|
||||
)),
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
) {
|
||||
peer_close_requested_stop = true;
|
||||
if request_group_stop_once(&mut stop_requested) {
|
||||
session.stop();
|
||||
}
|
||||
session.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ use crate::{
|
||||
cmd::tui::args::{ResolvedTuiTarget, TuiArgs},
|
||||
shared::client::{
|
||||
is_shutdown_requested,
|
||||
session::{peer_close_run_error, request_group_stop_once, should_stop_group_on_peer_close},
|
||||
session::{
|
||||
peer_close_run_error, request_group_stop_for_peer_close, request_group_stop_once,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -200,6 +202,15 @@ fn run_group_tui(
|
||||
session.stop();
|
||||
}
|
||||
}
|
||||
if request_group_stop_for_peer_close(
|
||||
args.is_continuous(),
|
||||
interrupted,
|
||||
session.peer_closed_target_count(),
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
) {
|
||||
session.stop();
|
||||
}
|
||||
|
||||
match events.try_recv() {
|
||||
Ok(Some(group_event)) => {
|
||||
@@ -212,15 +223,17 @@ fn run_group_tui(
|
||||
ManagedGroupEvent::TargetFinished(target) => {
|
||||
terminal_targets.insert(target.id.as_str().to_owned());
|
||||
state.process_target_outcome(&target);
|
||||
if should_stop_group_on_peer_close(
|
||||
if request_group_stop_for_peer_close(
|
||||
args.is_continuous(),
|
||||
interrupted,
|
||||
&target.end_reason,
|
||||
u64::from(matches!(
|
||||
&target.end_reason,
|
||||
irtt_client::ManagedTargetEndReason::PeerClosed
|
||||
)),
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
) {
|
||||
peer_close_requested_stop = true;
|
||||
if request_group_stop_once(&mut stop_requested) {
|
||||
session.stop();
|
||||
}
|
||||
session.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,21 +566,41 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continuous_group_peer_close_requests_stop_unless_interrupted() {
|
||||
assert!(should_stop_group_on_peer_close(
|
||||
fn continuous_group_reliable_peer_close_status_requests_stop_once() {
|
||||
let mut peer_close_requested_stop = false;
|
||||
let mut stop_requested = false;
|
||||
assert!(request_group_stop_for_peer_close(
|
||||
true,
|
||||
false,
|
||||
&irtt_client::ManagedTargetEndReason::PeerClosed
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!should_stop_group_on_peer_close(
|
||||
assert!(peer_close_requested_stop);
|
||||
assert!(stop_requested);
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
&irtt_client::ManagedTargetEndReason::PeerClosed
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!should_stop_group_on_peer_close(
|
||||
|
||||
let mut peer_close_requested_stop = false;
|
||||
let mut stop_requested = false;
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
false,
|
||||
false,
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
true,
|
||||
true,
|
||||
&irtt_client::ManagedTargetEndReason::PeerClosed
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use irtt_client::ManagedTargetEndReason;
|
||||
|
||||
pub fn is_shutdown_requested(shutdown_requested: &AtomicBool) -> bool {
|
||||
shutdown_requested.load(Ordering::Relaxed)
|
||||
}
|
||||
@@ -29,12 +27,18 @@ pub fn peer_close_run_error(
|
||||
))
|
||||
}
|
||||
|
||||
pub fn should_stop_group_on_peer_close(
|
||||
pub fn request_group_stop_for_peer_close(
|
||||
continuous: bool,
|
||||
interrupted: bool,
|
||||
end_reason: &ManagedTargetEndReason,
|
||||
peer_closed_target_count: u64,
|
||||
peer_close_requested_stop: &mut bool,
|
||||
stop_requested: &mut bool,
|
||||
) -> bool {
|
||||
continuous && !interrupted && matches!(end_reason, ManagedTargetEndReason::PeerClosed)
|
||||
if !continuous || interrupted || peer_closed_target_count == 0 {
|
||||
return false;
|
||||
}
|
||||
*peer_close_requested_stop = true;
|
||||
request_group_stop_once(stop_requested)
|
||||
}
|
||||
|
||||
pub fn request_group_stop_once(stop_requested: &mut bool) -> bool {
|
||||
@@ -65,30 +69,48 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grouped_peer_close_stop_policy_is_run_mode_and_interruption_aware() {
|
||||
assert!(should_stop_group_on_peer_close(
|
||||
true,
|
||||
false,
|
||||
&ManagedTargetEndReason::PeerClosed
|
||||
));
|
||||
assert!(!should_stop_group_on_peer_close(
|
||||
false,
|
||||
false,
|
||||
&ManagedTargetEndReason::PeerClosed
|
||||
));
|
||||
assert!(!should_stop_group_on_peer_close(
|
||||
true,
|
||||
true,
|
||||
&ManagedTargetEndReason::PeerClosed
|
||||
));
|
||||
assert!(!should_stop_group_on_peer_close(
|
||||
true,
|
||||
false,
|
||||
&ManagedTargetEndReason::TestComplete
|
||||
));
|
||||
|
||||
fn grouped_peer_close_stop_policy_is_run_mode_and_one_shot() {
|
||||
let mut peer_close_requested_stop = false;
|
||||
let mut stop_requested = false;
|
||||
assert!(request_group_stop_once(&mut stop_requested));
|
||||
assert!(!request_group_stop_once(&mut stop_requested));
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
false,
|
||||
false,
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
true,
|
||||
true,
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(!peer_close_requested_stop);
|
||||
assert!(!stop_requested);
|
||||
|
||||
assert!(request_group_stop_for_peer_close(
|
||||
true,
|
||||
false,
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
assert!(peer_close_requested_stop);
|
||||
assert!(stop_requested);
|
||||
assert!(!request_group_stop_for_peer_close(
|
||||
true,
|
||||
false,
|
||||
1,
|
||||
&mut peer_close_requested_stop,
|
||||
&mut stop_requested,
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user