From fe7eb38253ac18908604b0f95e203d4de35c6374 Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Thu, 6 Nov 2025 19:36:45 -0800 Subject: [PATCH] Refactor: Ensure heartbeat alarm is always cleared --- index.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 537e210..60e5c04 100644 --- a/index.js +++ b/index.js @@ -82,6 +82,15 @@ export class MyDurableObject { bcast(obj) { this.sockets.forEach(ws => this.send(ws, obj)); } + notify(msg, pri = 3, tags = []) { + if (!this.env.NTFY_TOPIC) return; + this.state.waitUntil(fetch(`https://ntfy.sh/${this.env.NTFY_TOPIC}`, { + method: 'POST', + body: msg, + headers: { 'Title': 'Sune ORP', 'Priority': `${pri}`, 'Tags': tags.join(',') }, + }).catch(e => console.error('ntfy failed:', e))); + } + async autopsy() { if (this.rid) return; const snap = await this.state.storage.get('run').catch(() => null); @@ -103,6 +112,7 @@ export class MyDurableObject { this.phase = 'evicted'; this.error = 'The run was interrupted due to system eviction.'; this.saveSnapshot(); + this.notify(`Run ${this.rid} evicted`, 4, ['warning']); await this.stopHeartbeat(); } } @@ -337,6 +347,7 @@ export class MyDurableObject { try { this.oaStream?.controller?.abort(); } catch {} this.saveSnapshot(); this.bcast({ type: 'err', message: this.error }); + this.notify(`Run ${this.rid} failed: ${this.error}`, 4, ['rotating_light']); this.state.waitUntil(this.stopHeartbeat()); } @@ -348,12 +359,14 @@ export class MyDurableObject { async stopHeartbeat() { this.hbActive = false; + const ageSeconds = (this.age * HB_INTERVAL_MS) / 1000; + this.notify(`Run ${this.rid} ended. Phase: ${this.phase}. Age: ${ageSeconds.toFixed(1)}s.`, 3, ['stop_sign']); await this.state.storage.setAlarm(null).catch(() => {}); } async Heart() { if (this.phase !== 'running' || !this.hbActive) return this.stopHeartbeat(); - if (++this.age * HB_INTERVAL_MS >= MAX_RUN_MS) return this.fail('Run timed out after 15 minutes.'); + if (++this.age * HB_INTERVAL_MS >= MAX_RUN_MS) return this.fail(`Run timed out after ${MAX_RUN_MS / 60000} minutes.`); await this.state.storage.setAlarm(Date.now() + HB_INTERVAL_MS).catch(() => {}); } @@ -408,4 +421,3 @@ export class MyDurableObject { return contents; } } -