Compare commits

..

No commits in common. "fb1c239e152c2db8ce567afe495e1461ce49ce6d" and "662dd21a60acbd4ae12225af2736b4c2cd6fc8be" have entirely different histories.

View file

@ -1,5 +1,5 @@
import "websocket-polyfill"; import "websocket-polyfill";
import NDK, { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKRpcRequest, NDKRpcResponse, NDKUser } from '@nostr-dev-kit/ndk'; import NDK, { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKRpcRequest, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
import { NDKNostrRpc } from '@nostr-dev-kit/ndk'; import { NDKNostrRpc } from '@nostr-dev-kit/ndk';
import createDebug from 'debug'; import createDebug from 'debug';
import { Key, KeyUser } from '../run'; import { Key, KeyUser } from '../run';
@ -168,17 +168,12 @@ class AdminInterface {
this.handleRequest(req); this.handleRequest(req);
}); });
// Connection watchdog: exit if pool reports no connected relays // pingOrDie disabled — NDK 2.8.1 outbox model doesn't echo
// for >60s so the process supervisor (systemd / docker restart // self-published events back through subscriptions on
// policy / k8s) can recover. Replaces the original self-echo // non-public relay channels, so the watchdog fires false
// pingOrDie — see relayConnectionWatchdog comment + #4 + #7. // positives and exits the bunker every 50s on private relays.
// Operators with external liveness checking can disable via // See aiolabs/nsecbunkerd#4 + #7.
// NSEC_BUNKER_DISABLE_WATCHDOG=1. // pingOrDie(this.ndk);
if (process.env.NSEC_BUNKER_DISABLE_WATCHDOG !== '1') {
relayConnectionWatchdog(this.ndk);
} else {
console.log('⏸ watchdog disabled via NSEC_BUNKER_DISABLE_WATCHDOG=1');
}
}).catch((err) => { }).catch((err) => {
console.log('❌ admin connection failed'); console.log('❌ admin connection failed');
console.log(err); console.log(err);
@ -459,47 +454,44 @@ class AdminInterface {
} }
} }
/** async function pingOrDie(ndk: NDK) {
* Pool-status connection watchdog. Exits the daemon if every relay in let deathTimer: NodeJS.Timeout | null = null;
* the pool stays disconnected for longer than PARTITION_THRESHOLD_MS.
* function resetDeath() {
* Replaces the original `pingOrDie` self-echo watchdog, which published if (deathTimer) clearTimeout(deathTimer);
* a kind-24133 event to its own pubkey every 20s and exited if it deathTimer = setTimeout(() => {
* didn't see the echo within 50s. That works on public relays but console.log(`❌ No ping event received in 30 seconds. Exiting.`);
* silently breaks on single-private-relay setups: NDK 2.8.1's outbox process.exit(1);
* model doesn't reliably route self-publishes back through the }, 50000);
* matching subscription, so the watchdog fires false positives and }
* exits the daemon every 50s while RPCs over the same channel still
* work fine. See aiolabs/nsecbunkerd#4 + #7. const self = await ndk.signer!.user();
* const sub = ndk.subscribe({
* The pool-status approach uses NDK's own connection-lifecycle authors: [self.pubkey],
* tracking `pool.connectedRelays()` reports relays in kinds: [NDKKind.NostrConnect],
* NDKRelayStatus.CONNECTED which is reliable across all relay "#p": [self.pubkey]
* configurations because it doesn't depend on round-trip });
* publish/subscribe. No event is published; no relay traffic. sub.on("event", (event: NDKEvent) => {
* console.log(`🔔 Received ping event:`, event.created_at);
* Detects partition within POLL_INTERVAL + PARTITION_THRESHOLD ms. resetDeath();
* Transient disconnects shorter than PARTITION_THRESHOLD don't trip });
* the watchdog useful for relays that flap or briefly drop on sub.start();
* network blips.
*/ resetDeath();
async function relayConnectionWatchdog(ndk: NDK) {
const POLL_INTERVAL_MS = 10_000;
const PARTITION_THRESHOLD_MS = 60_000;
let lastConnectedAt = Date.now();
setInterval(() => { setInterval(() => {
const connectedCount = ndk.pool.connectedRelays().length; const event = new NDKEvent(ndk, {
if (connectedCount > 0) { kind: NDKKind.NostrConnect,
lastConnectedAt = Date.now(); tags: [ ["p", self.pubkey] ],
return; content: "ping"
} } as NostrEvent);
const elapsed = Date.now() - lastConnectedAt; event.publish().then(() => {
if (elapsed > PARTITION_THRESHOLD_MS) { console.log(`🔔 Sent ping event:`, event.created_at);
console.log(`❌ No connected relays for ${Math.floor(elapsed / 1000)}s. Exiting.`); }).catch((e: any) => {
console.log(`❌ Failed to send ping event:`, e.message);
process.exit(1); process.exit(1);
} });
}, POLL_INTERVAL_MS); }, 20000);
} }
export default AdminInterface; export default AdminInterface;