thinkpool-pair 0.7.59 → 0.7.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/account.mjs +20 -2
- package/package.json +1 -1
package/account.mjs
CHANGED
|
@@ -223,6 +223,7 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
223
223
|
// codes + version) on a per-account channel; the dashboard subscribes read-only.
|
|
224
224
|
const machine = os.hostname().replace(/\.local$/, '')
|
|
225
225
|
const acct = sb.channel(`tpacct:${session.user.id}`, { config: { presence: { key: machine }, broadcast: { self: false } } })
|
|
226
|
+
let restarting = false // set by the "restart" broadcast → stop() exits non-zero so a supervisor respawns us
|
|
226
227
|
// Dashboard "Disconnect" → broadcast shutdown → clean exit (presence leaves, bar flips live).
|
|
227
228
|
// If we're the auto-restarting background service (launchd KeepAlive / systemd
|
|
228
229
|
// Restart=always sets AUTOUPDATE=1), a bare exit would be respawned ~2s later —
|
|
@@ -244,6 +245,20 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
244
245
|
}
|
|
245
246
|
process.kill(process.pid, 'SIGTERM')
|
|
246
247
|
})
|
|
248
|
+
// Dashboard "Restart" → broadcast restart → graceful stop with a NON-ZERO exit so
|
|
249
|
+
// EVERY supervisor respawns us: launchd KeepAlive / systemd Restart=always respawn
|
|
250
|
+
// regardless of exit code, and the bridge.mjs --supervise wrappers (cmux tier, room
|
|
251
|
+
// tier) respawn on non-zero but treat 0 as a clean stop. Children persist + resume
|
|
252
|
+
// their sessions (session-store), so the bounce is invisible in-room. Unlike shutdown
|
|
253
|
+
// we do NOT uninstall the service. A plain foreground bridge has no supervisor, so it
|
|
254
|
+
// just stops — restart is meaningful for the always-on bridge. Old bridges (pre-0.7.60)
|
|
255
|
+
// don't subscribe to this event, so the dashboard button is a harmless no-op there.
|
|
256
|
+
acct.on('broadcast', { event: 'restart' }, () => {
|
|
257
|
+
process.stderr.write('\n ◇ restart requested from the dashboard — bouncing bridge (sessions resume).\n')
|
|
258
|
+
restarting = true
|
|
259
|
+
setTimeout(() => { try { releaseSingleton() } catch { /* noop */ } process.exit(1) }, 2500)
|
|
260
|
+
process.kill(process.pid, 'SIGTERM')
|
|
261
|
+
})
|
|
247
262
|
const pushPresence = () => { try { acct.track({ name: machine, version: VERSION, rooms: [...children.keys()], ts: Date.now() }) } catch { /* noop */ } }
|
|
248
263
|
// Re-track on EVERY (re)subscribe, not just the first: a realtime reconnect
|
|
249
264
|
// (network blip, or a token swap mid-flight) rejoins the channel and must
|
|
@@ -319,16 +334,19 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
319
334
|
await tick()
|
|
320
335
|
const iv = setInterval(tick, 15000)
|
|
321
336
|
let stopping = false
|
|
337
|
+
// restart-vs-stop is the ONLY difference in exit code: a web "restart" sets this so
|
|
338
|
+
// we exit non-zero (every supervisor respawns); a normal stop/shutdown exits 0.
|
|
322
339
|
const stop = (sig) => {
|
|
323
340
|
if (stopping) return; stopping = true
|
|
341
|
+
const code = restarting ? 1 : 0
|
|
324
342
|
clearInterval(iv)
|
|
325
343
|
keepFresh.cancel()
|
|
326
344
|
releaseSingleton()
|
|
327
345
|
for (const c of children.values()) { try { c.kill(sig || 'SIGTERM') } catch { /* noop */ } }
|
|
328
346
|
// Flush the presence LEAVE before exiting so the dashboard flips to
|
|
329
347
|
// "not connected" in realtime (don't fire-and-forget the untrack).
|
|
330
|
-
;(async () => { try { await acct.untrack() } catch { /* noop */ } try { await sb.removeChannel(acct) } catch { /* noop */ } process.exit(
|
|
331
|
-
setTimeout(() => process.exit(
|
|
348
|
+
;(async () => { try { await acct.untrack() } catch { /* noop */ } try { await sb.removeChannel(acct) } catch { /* noop */ } process.exit(code) })()
|
|
349
|
+
setTimeout(() => process.exit(code), 1500) // hard backstop if the flush hangs
|
|
332
350
|
}
|
|
333
351
|
for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(sig, () => stop(sig))
|
|
334
352
|
|