From d380db741b5f642bead06e04db6c0eaff7fe7baa Mon Sep 17 00:00:00 2001 From: ops Date: Fri, 14 Aug 2026 17:35:10 +0000 Subject: [PATCH] bin.js: exit on dead sbot connection instead of wedging ssb-viewer holds one muxrpc handle captured in a closure and has no reconnect path. When sbot is OOM-killed and restarted by run-server.sh, the viewer kept port 8807 open while holding a dead connection and never answered again -- the silent wedge. Listen for muxrpc closed and exit(1) so the while-loop in run-ssb-viewer.sh restarts with a fresh connection. Also poll whoami to catch half-open connections where closed never fires. Verified: killing sbot now self-heals in ~4s instead of hanging. --- bin.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/bin.js b/bin.js index b31c243..b1fde83 100755 --- a/bin.js +++ b/bin.js @@ -1,6 +1,49 @@ #!/usr/bin/env node +// ssb-viewer connects to sbot exactly once and hands the handle to index.js, +// which captures it in a closure behind http.createServer().listen(). There is +// no reconnect. So when sbot dies -- which on this box means "gets OOM-killed", +// after which run-server.sh restarts it -- the viewer keeps port 8807 open +// while holding a dead muxrpc connection, and never answers another request. +// +// That is the silent wedge. The fix is not to reconnect (index.js can't take a +// new handle) but to exit loudly, so the `while true` loop in run-ssb-viewer.sh +// restarts us with a fresh connection. + +var PING_INTERVAL_MS = 60000 +var PING_TIMEOUT_MS = 20000 + +function bail (why) { + console.error('[viewer] ' + new Date().toISOString() + ' ' + why + ' — exiting so the run loop restarts us') + process.exit(1) +} + require('ssb-client')(function (err, sbot, config) { - if (err) throw err + // ssb-client already wraps this as "could not connect to sbot", so don't + // prefix it again. + if (err) return bail(String(err.message || err)) + + // muxrpc emits 'closed' when the underlying stream ends + // (see node_modules/muxrpc/index.js). This is the fast path. + sbot.on('closed', function () { + bail('sbot connection closed') + }) + + // Belt and braces: a half-open TCP connection can leave 'closed' unfired + // while calls silently hang forever. Poll a cheap RPC to catch that case. + if (typeof sbot.whoami === 'function') { + var timer = setInterval(function () { + var timeout = setTimeout(function () { + bail('sbot did not answer whoami within ' + (PING_TIMEOUT_MS / 1000) + 's') + }, PING_TIMEOUT_MS) + sbot.whoami(function (err) { + clearTimeout(timeout) + if (err) bail('sbot whoami failed: ' + (err.message || err)) + }) + }, PING_INTERVAL_MS) + // Don't hold the event loop open on our account. + timer.unref() + } + require('.').init(sbot, config) })