Files
custo-viewer/bin.js
T
ops d380db741b 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.
2026-08-14 17:35:10 +00:00

50 lines
1.9 KiB
JavaScript
Executable File

#!/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) {
// 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)
})