fix(bridge): dial the configured port, and back off when refused (D154, D155) #15

Merged
whitlocktech merged 2 commits from fix/config-before-link into main 2026-09-26 01:27:03 -05:00
Showing only changes of commit 3e928bb2f6 - Show all commits

View File

@@ -65,6 +65,15 @@ namespace Oxide.Plugins
/// </summary>
private const int MaxBackoffMs = 5000;
/// <summary>
/// How long a link must stay up before its drop counts as an outage rather than a
/// refusal. The backoff resets only past it: a sidecar that closes every connection at
/// once — one refusing a plugin that names another server (D155), or one crash-looping —
/// would otherwise be redialled twice a second for ever, rebuilding the boards on the
/// main thread and printing two console lines each time.
/// </summary>
private const int StableLinkMs = 10000;
/// <summary>The longest line accepted from the sidecar. Over-long lines are discarded.</summary>
private const int MaxInboundLineBytes = 1024 * 1024;
@@ -570,6 +579,7 @@ namespace Oxide.Plugins
{
TcpClient client = null;
Thread reader = null;
System.Diagnostics.Stopwatch upFor = null;
int epoch = Interlocked.Increment(ref _epoch);
@@ -588,7 +598,7 @@ namespace Oxide.Plugins
_dead = false;
_connected = true;
_loggedConnectFailure = false; // so a LATER outage is reported again
backoffMs = 500;
upFor = System.Diagnostics.Stopwatch.StartNew();
Interlocked.Increment(ref _connects);
Puts($"connected to {host}:{port}");
@@ -660,14 +670,25 @@ namespace Oxide.Plugins
if (!_running)
break;
// A link that held is an outage: start again from the shortest wait. One that was
// closed on arrival keeps doubling (see StableLinkMs).
if (upFor != null && upFor.ElapsedMilliseconds >= StableLinkMs)
backoffMs = 500;
// Nothing is listening yet, or the sidecar restarted. Both are normal.
//
// `Wake`, not `Thread.Sleep`: Unload runs on the MAIN thread and joins this one, so
// an uninterruptible sleep here is a stall of up to MaxBackoffMs on every reload —
// Oxide reports it as `Calling 'Unload' took 1918ms`, and the server is frozen for
// that whole time. Unload sets `_running` false and signals `Wake`, so waiting on
// the handle turns that stall into an immediate return.
Wake.WaitOne(backoffMs);
// A handle, not `Thread.Sleep`: Unload runs on the MAIN thread and joins this one,
// so an uninterruptible sleep here is a stall of up to MaxBackoffMs on every reload
// — Oxide reports it as `Calling 'Unload' took 1918ms`, and the server is frozen for
// that whole time. Unload sets `_stopping`, so waiting on it turns that stall into
// an immediate return.
//
// `_stopping`, not `Wake`, for the reason `_stopping` gives: `Emit` signals `Wake`
// on every frame, so a backoff waited on it lasted until the next hook fired. That
// was invisible while a failed connect was silent; against a sidecar that refuses
// (D155) the phase 18 walk measured some 250 redials a second, each printing two
// console lines and rebuilding the boards.
_stopping.WaitOne(backoffMs);
backoffMs = Math.Min(backoffMs * 2, MaxBackoffMs);
}