probe: fix mirrored start deadlock

This commit is contained in:
Brad Stein 2026-05-01 11:13:20 -03:00
parent 0d9121f921
commit 5cf89c2574
7 changed files with 22 additions and 8 deletions

6
Cargo.lock generated
View File

@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "lesavka_client" name = "lesavka_client"
version = "0.16.15" version = "0.16.16"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1686,7 +1686,7 @@ dependencies = [
[[package]] [[package]]
name = "lesavka_common" name = "lesavka_common"
version = "0.16.15" version = "0.16.16"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",
@ -1698,7 +1698,7 @@ dependencies = [
[[package]] [[package]]
name = "lesavka_server" name = "lesavka_server"
version = "0.16.15" version = "0.16.16"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",

View File

@ -4,7 +4,7 @@ path = "src/main.rs"
[package] [package]
name = "lesavka_client" name = "lesavka_client"
version = "0.16.15" version = "0.16.16"
edition = "2024" edition = "2024"
[dependencies] [dependencies]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "lesavka_common" name = "lesavka_common"
version = "0.16.15" version = "0.16.16"
edition = "2024" edition = "2024"
build = "build.rs" build = "build.rs"

View File

@ -23,7 +23,7 @@ class ProbeState:
self.output_path = output_path self.output_path = output_path
self.status_path = status_path self.status_path = status_path
self.duration_seconds = duration_seconds self.duration_seconds = duration_seconds
self.lock = threading.Lock() self.lock = threading.RLock()
self.start_token = 0 self.start_token = 0
self.status = { self.status = {
"booted_at": time.time(), "booted_at": time.time(),

View File

@ -43,7 +43,7 @@ class StimulusState:
def __init__(self, status_path: Path, args: argparse.Namespace) -> None: def __init__(self, status_path: Path, args: argparse.Namespace) -> None:
self.status_path = status_path self.status_path = status_path
self.args = args self.args = args
self.lock = threading.Lock() self.lock = threading.RLock()
self.start_token = 0 self.start_token = 0
self.status = { self.status = {
"booted_at": time.time(), "booted_at": time.time(),

View File

@ -10,7 +10,7 @@ bench = false
[package] [package]
name = "lesavka_server" name = "lesavka_server"
version = "0.16.15" version = "0.16.16"
edition = "2024" edition = "2024"
autobins = false autobins = false

View File

@ -124,3 +124,17 @@ fn local_stimulus_matches_sync_analyzer_pulse_contract() {
); );
} }
} }
#[test]
fn manual_probe_python_servers_use_reentrant_state_locks() {
const BROWSER_CONSUMER: &str = include_str!("../../scripts/manual/browser_consumer_probe.py");
for (name, script) in [
("local stimulus", LOCAL_STIMULUS),
("browser consumer", BROWSER_CONSUMER),
] {
assert!(
script.contains("threading.RLock()"),
"{name} server request handlers call snapshot while holding state lock; use RLock to avoid /start deadlocks"
);
}
}