test(galaxy): de-flake writer-lane and supervisor tests; align EffectiveTimeout doc
The writer concurrency fake parks on its release signal (the 300 ms delay could release the gate early on a starved pool), the supervisor test's cross-thread hold flag is Volatile, and the EffectiveTimeout doc now states the 1 s floor the code and tests implement. Refs #735 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -165,7 +165,9 @@ public sealed class GalaxyDriverProbe : IDriverProbe
|
||||
/// config's <see cref="GalaxyDriverOptions.ProbeTimeoutSeconds"/> when that is positive and
|
||||
/// shorter. The knob was authored by the AdminUI and parsed by the factory but consumed by
|
||||
/// nothing — the probe always ran on the caller's budget alone. A non-positive caller budget
|
||||
/// is treated as the config value (or 1 s when that is unset too), as before.
|
||||
/// is floored to 1 s before the comparison (the same floor <see cref="BuildProbeClientOptions"/>
|
||||
/// applies to the gRPC call budget), so the probe runs briefly rather than cancelling before
|
||||
/// it starts; a longer config value never raises it above that floor.
|
||||
/// </summary>
|
||||
/// <param name="callerTimeout">The budget the host handed the probe.</param>
|
||||
/// <param name="configuredSeconds">The config's <c>ProbeTimeoutSeconds</c>; ignored when not positive.</param>
|
||||
|
||||
+3
-1
@@ -51,7 +51,9 @@ public sealed class GatewayGalaxyDataWriterConcurrencyTests
|
||||
int seen;
|
||||
do { seen = Volatile.Read(ref _peak); } while (now > seen && Interlocked.CompareExchange(ref _peak, now, seen) != seen);
|
||||
if (now >= ReleaseAt) _release.TrySetResult();
|
||||
await Task.WhenAny(_release.Task, Task.Delay(300, ct));
|
||||
// Park on the signal; the delay is only a safety net against a wedged test (a starved
|
||||
// pool must not release the gate early and turn the peak assertion flaky).
|
||||
await Task.WhenAny(_release.Task, Task.Delay(WaitMs, ct));
|
||||
Interlocked.Decrement(ref _inFlight);
|
||||
return _handles.GetOrAdd(fullRef, r => HandleFor?.Invoke(r) ?? Interlocked.Increment(ref _nextHandle));
|
||||
}
|
||||
|
||||
+3
-3
@@ -23,11 +23,11 @@ public sealed class ReconnectSupervisorCycleCtsTests
|
||||
{
|
||||
var holdReopen = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var reopenEntered = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var hold = false;
|
||||
var hold = new[] { false }; // read on the recovery loop's thread, written here — Volatile both ways
|
||||
using var sup = new ReconnectSupervisor(
|
||||
reopen: async _ =>
|
||||
{
|
||||
if (hold)
|
||||
if (Volatile.Read(ref hold[0]))
|
||||
{
|
||||
reopenEntered.TrySetResult();
|
||||
await holdReopen.Task;
|
||||
@@ -45,7 +45,7 @@ public sealed class ReconnectSupervisorCycleCtsTests
|
||||
sup.CyclesStarted.ShouldBe(3);
|
||||
|
||||
// Positive control: a cycle parked inside reopen still holds its CTS.
|
||||
hold = true;
|
||||
Volatile.Write(ref hold[0], true);
|
||||
sup.ReportTransportFailure(new IOException("drop 3"));
|
||||
(await Task.WhenAny(reopenEntered.Task, Task.Delay(WaitMs))).ShouldBe(reopenEntered.Task);
|
||||
sup.CyclesStarted.ShouldBe(4);
|
||||
|
||||
Reference in New Issue
Block a user