feat: retry failed alert deliveries

This commit is contained in:
2026-07-19 12:58:53 +08:00
parent 00928b72e4
commit 1e01f3295e
9 changed files with 74 additions and 9 deletions
+26
View File
@@ -0,0 +1,26 @@
import assert from "node:assert/strict";
import { after, test } from "node:test";
import { randomUUID } from "node:crypto";
import { rmSync } from "node:fs";
const databasePath = `/tmp/mebbling-alerts-${randomUUID()}.db`;
process.env.DATABASE_PATH = databasePath;
process.env.ALERT_WEBHOOK_URL = "https://alerts.example.test/hook";
delete process.env.HUB_BUILD;
let database: typeof import("../lib/db").db | undefined;
after(() => { database?.close(); rmSync(databasePath, { force: true }); rmSync(`${databasePath}-wal`, { force: true }); rmSync(`${databasePath}-shm`, { force: true }); delete process.env.ALERT_WEBHOOK_URL; });
test("persists failed alerts for exponential-backoff retry", async () => {
const { db } = await import("../lib/db"); database = db;
const { deliverNextAlert, sendAlert } = await import("../lib/alerts");
assert.equal(sendAlert("test", "Test alert", "delivery should retry"), true);
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => new Response("unavailable", { status: 503 });
try { assert.equal(await deliverNextAlert(), true); } finally { globalThis.fetch = originalFetch; }
const delivery = db.prepare("SELECT status,attempts,last_error FROM alert_deliveries").get() as { status: string; attempts: number; last_error: string };
assert.equal(delivery.status, "queued");
assert.equal(delivery.attempts, 1);
assert.match(delivery.last_error, /503/);
});
+1 -1
View File
@@ -16,7 +16,7 @@ test("applies tracked migrations and deduplicates active pull jobs", async () =>
const { queuePull } = await import("../lib/sync");
const { notify } = await import("../lib/notifications");
const migrations = db.prepare("SELECT version FROM schema_migrations ORDER BY version").all() as { version: number }[];
assert.deepEqual(migrations.map((item) => item.version), Array.from({ length: 40 }, (_, index) => index + 1));
assert.deepEqual(migrations.map((item) => item.version), Array.from({ length: 41 }, (_, index) => index + 1));
const userId = Number(db.prepare("INSERT INTO users(username,password_hash) VALUES('sync-test','hash')").run().lastInsertRowid);
const sourceId = Number(db.prepare("INSERT INTO sources(user_id,name,base_url,token_encrypted,is_enabled) VALUES(?,?,?,?,1)").run(userId, "Test", "https://example.test", "encrypted").lastInsertRowid);
assert.equal(queuePull(sourceId, "manual"), true);