mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-22 15:52:22 +00:00
fix(nests-tests): per-method relay reset + 2 s catalog timeout
Two further hardenings on top of the catalog-retry fix to drive full-suite stability: - `NativeMoqRelayHarness.resetShared()` — tears down the current shared relay subprocess and lets the next caller spawn a fresh one. ~500 ms cost per call (cargo binaries cached, only relay boot + UDP bind paid). - `HangInteropTest.@BeforeTest` calls `resetShared()` so each scenario gets a clean relay; eliminates the per-subscriber- forward-queue + announce-table state that was accumulating across the 11 sequential tests in one JVM run. - hang-listen catalog read per-attempt timeout bumped from 500 ms → 2 s. Under concurrent-test load the wire round- trip can exceed 500 ms; longer per-attempt budget keeps the happy path fast (resolves on the first attempt) while tolerating slow handshakes. Suite wallclock cost: ~5–6 s added (one fresh relay boot per scenario), bringing a typical run to ~2:30. Stability gain is the trade. Note: full-suite stability isn't reverified in this commit — running the suite repeatedly under three concurrent agent worktrees (I7 reconnect, Phase 4 browser, I6 multi-listener) caused massive resource contention. Will re-verify once the parallel agents have completed and pushed. https://claude.ai/code/session_01ERJPUYfdLPwZ99pr5EcEcV
This commit is contained in:
@@ -89,6 +89,15 @@ class HangInteropTest {
|
||||
@BeforeTest
|
||||
fun gate() {
|
||||
NativeMoqRelayHarness.assumeHangInterop()
|
||||
// Reset the shared relay subprocess between scenarios.
|
||||
// Sharing across all 11 methods in one JVM run means the
|
||||
// relay's per-subscriber forward queues + announce
|
||||
// tables accumulate state from prior tests, manifesting
|
||||
// as intermittent catalog-cancel + sample-count flakes
|
||||
// that don't reproduce in isolation. Per-method reboot
|
||||
// costs ~500 ms (cargo binaries are cached) — acceptable
|
||||
// for the stability gain.
|
||||
NativeMoqRelayHarness.resetShared()
|
||||
}
|
||||
|
||||
/** I1: 5 s 440 Hz mono sine, asserted via FFT peak + ZCR. */
|
||||
|
||||
@@ -153,6 +153,29 @@ class NativeMoqRelayHarness private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the current shared relay subprocess and start a
|
||||
* fresh one. Used as a JUnit `@Before` hook by tests that
|
||||
* need clean per-method relay state — under accumulated
|
||||
* cross-test broadcasts / connections the relay's per-
|
||||
* subscriber forward queues drift, manifesting as
|
||||
* intermittent catalog-cancel and sample-count flakes that
|
||||
* don't reproduce in isolation.
|
||||
*
|
||||
* Cost: ~500 ms per call (cargo binaries are cached, only
|
||||
* the subprocess boot + UDP bind + first client handshake
|
||||
* are paid). At 11 scenarios × 500 ms that's ~5.5 s added
|
||||
* to the suite wallclock — acceptable trade for stability.
|
||||
*/
|
||||
fun resetShared() {
|
||||
synchronized(sharedLock) {
|
||||
shared?.let {
|
||||
runCatching { it.close() }
|
||||
}
|
||||
shared = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun doStart(): NativeMoqRelayHarness {
|
||||
check(isEnabled()) {
|
||||
"NativeMoqRelayHarness.shared() called without -D$ENABLE_PROPERTY=true."
|
||||
|
||||
@@ -168,11 +168,15 @@ async fn listen(
|
||||
// Subscribe to the catalog and read the first published
|
||||
// version. The catalog hook in Amethyst's
|
||||
// `MoqLiteNestsSpeaker` (`setOnNewSubscriber`) can race the
|
||||
// SUBSCRIBE bidi mid-suite — under accumulated state the
|
||||
// first try sometimes resolves with a "cancelled" stream
|
||||
// before the catalog frame arrives. Retry up to twice with
|
||||
// a fresh subscribe; total wallclock ≤ 1 s, well inside
|
||||
// the test's broadcast window.
|
||||
// SUBSCRIBE bidi mid-suite — under accumulated relay state
|
||||
// the first try sometimes resolves with "cancelled" before
|
||||
// the catalog frame arrives. Retry up to 3 times with a
|
||||
// 2 s per-attempt timeout (6 s total worst case). Under
|
||||
// concurrent load (multiple jvmTest workers contending for
|
||||
// the relay) the first attempt's wire round-trip can
|
||||
// exceed 500 ms; the longer per-attempt budget keeps the
|
||||
// happy-path fast (resolves on the first attempt) while
|
||||
// tolerating slow handshakes.
|
||||
let info = {
|
||||
let mut last_err: Option<anyhow::Error> = None;
|
||||
let mut decoded: Option<hang::Catalog> = None;
|
||||
@@ -181,7 +185,7 @@ async fn listen(
|
||||
.subscribe_track(&hang::Catalog::default_track())
|
||||
.context("subscribe catalog")?;
|
||||
let mut catalog = hang::CatalogConsumer::new(catalog_track);
|
||||
match tokio::time::timeout(Duration::from_millis(500), catalog.next()).await {
|
||||
match tokio::time::timeout(Duration::from_secs(2), catalog.next()).await {
|
||||
Ok(Ok(Some(c))) => {
|
||||
decoded = Some(c);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user