openvibers/openvibe.media Commits
Shorten webhook retry waits in tests without patching global setTimeout
Changes
@@@ -42,6 +42,11 @@ function stats() {/** Test-only: forget every tally. */function _resetStats() { tallies.clear(); }++// Test-only: the base of the retry wait (null restores RETRY_BASE_MS), so a test never patches the++// global setTimeout the database pool's own timers use.++let retryBaseMs = RETRY_BASE_MS;++function _setRetryBaseMs(ms) { retryBaseMs = ms == null ? RETRY_BASE_MS : ms; }++function sign(secret, rawBody) {return 'sha256=' + crypto.createHmac('sha256', String(secret || '')).update(rawBody).digest('hex');}@@@ -99,7 +104,7 @@ async function sendWebhook(appOrId, event, data, { eventId = null } = {}) {console.warn(`[Webhooks] ${event} → ${app.app_id} failed after ${MAX_ATTEMPTS} attempts: ${err.message}`);return false;}-- await new Promise(r => setTimeout(r, RETRY_BASE_MS * attempt));++ await new Promise(r => setTimeout(r, retryBaseMs * attempt));}}return false;@@@ -129,4 +134,4 @@ async function announce(appId, event, { change = null, payload }) {return { data, eventId };}--module.exports = { sendWebhook, announce, sign, stats, _resetStats };++module.exports = { sendWebhook, announce, sign, stats, _resetStats, _setRetryBaseMs };@@@ -389,14 +389,18 @@ const http = require('http');const hooks = require('../server/webhooks');hooks._resetStats();await db.run("UPDATE apps SET webhook_url = 'https://hooks-down.example.test/never' WHERE app_id = 'tools'");-- const realFetch = global.fetch, realSetTimeout = global.setTimeout;-- global.setTimeout = (fn) => realSetTimeout(fn, 0); // retries must not slow the suite-- global.fetch = async (url) => ({ ok: String(url).includes('hooks.example.test'), status: String(url).includes('hooks.example.test') ? 200 : 500 });++ const realFetch = global.fetch;++ hooks._setRetryBaseMs(0); // retries must not slow the suite (never a global setTimeout patch: the pg pool's timers use it)++ global.fetch = async (url, opts) => {++ const u = String(url);++ if (!u.includes('hooks.example.test') && !u.includes('hooks-down.example.test')) return realFetch(url, opts);++ return { ok: u.includes('hooks.example.test'), status: u.includes('hooks.example.test') ? 200 : 500 };++ };try {assert.strictEqual(await hooks.sendWebhook('live', 'vod.ready', { id: 1 }), true);assert.strictEqual(await hooks.sendWebhook('tools', 'clip.ready', { id: 2 }), false);} finally {-- global.fetch = realFetch; global.setTimeout = realSetTimeout;++ global.fetch = realFetch; hooks._setRetryBaseMs(null);await db.run("UPDATE apps SET webhook_url = NULL, webhook_secret = NULL WHERE app_id = 'tools'");}const st = hooks.stats();
@@ -42,6 +42,11 @@ function stats() {
@@ -42,6 +42,11 @@ function stats() {
/** Test-only: forget every tally. */
/** Test-only: forget every tally. */
function _resetStats() { tallies.clear(); }
function _resetStats() { tallies.clear(); }
+// Test-only: the base of the retry wait (null restores RETRY_BASE_MS), so a test never patches the
+// global setTimeout the database pool's own timers use.
+let retryBaseMs = RETRY_BASE_MS;
+function _setRetryBaseMs(ms) { retryBaseMs = ms == null ? RETRY_BASE_MS : ms; }
+
function sign(secret, rawBody) {
function sign(secret, rawBody) {
return 'sha256=' + crypto.createHmac('sha256', String(secret || '')).update(rawBody).digest('hex');
return 'sha256=' + crypto.createHmac('sha256', String(secret || '')).update(rawBody).digest('hex');
}
}
@@ -99,7 +104,7 @@ async function sendWebhook(appOrId, event, data, { eventId = null } = {}) {
@@ -99,7 +104,7 @@ async function sendWebhook(appOrId, event, data, { eventId = null } = {}) {
console.warn(`[Webhooks] ${event} → ${app.app_id} failed after ${MAX_ATTEMPTS} attempts: ${err.message}`);
console.warn(`[Webhooks] ${event} → ${app.app_id} failed after ${MAX_ATTEMPTS} attempts: ${err.message}`);
return false;
return false;
}
}
- await new Promise(r => setTimeout(r, RETRY_BASE_MS * attempt));
+ await new Promise(r => setTimeout(r, retryBaseMs * attempt));
}
}
}
}
return false;
return false;
@@ -129,4 +134,4 @@ async function announce(appId, event, { change = null, payload }) {
@@ -129,4 +134,4 @@ async function announce(appId, event, { change = null, payload }) {
return { data, eventId };
return { data, eventId };
}
}
-module.exports = { sendWebhook, announce, sign, stats, _resetStats };
+module.exports = { sendWebhook, announce, sign, stats, _resetStats, _setRetryBaseMs };
@@ -389,14 +389,18 @@ const http = require('http');
@@ -389,14 +389,18 @@ const http = require('http');
const hooks = require('../server/webhooks');
const hooks = require('../server/webhooks');
hooks._resetStats();
hooks._resetStats();
await db.run("UPDATE apps SET webhook_url = 'https://hooks-down.example.test/never' WHERE app_id = 'tools'");
await db.run("UPDATE apps SET webhook_url = 'https://hooks-down.example.test/never' WHERE app_id = 'tools'");
- const realFetch = global.fetch, realSetTimeout = global.setTimeout;
- global.setTimeout = (fn) => realSetTimeout(fn, 0); // retries must not slow the suite
- global.fetch = async (url) => ({ ok: String(url).includes('hooks.example.test'), status: String(url).includes('hooks.example.test') ? 200 : 500 });
+ const realFetch = global.fetch;
+ hooks._setRetryBaseMs(0); // retries must not slow the suite (never a global setTimeout patch: the pg pool's timers use it)
+ global.fetch = async (url, opts) => {
+ const u = String(url);
+ if (!u.includes('hooks.example.test') && !u.includes('hooks-down.example.test')) return realFetch(url, opts);
+ return { ok: u.includes('hooks.example.test'), status: u.includes('hooks.example.test') ? 200 : 500 };
+ };
try {
try {
assert.strictEqual(await hooks.sendWebhook('live', 'vod.ready', { id: 1 }), true);
assert.strictEqual(await hooks.sendWebhook('live', 'vod.ready', { id: 1 }), true);
assert.strictEqual(await hooks.sendWebhook('tools', 'clip.ready', { id: 2 }), false);
assert.strictEqual(await hooks.sendWebhook('tools', 'clip.ready', { id: 2 }), false);
} finally {
} finally {
- global.fetch = realFetch; global.setTimeout = realSetTimeout;
+ global.fetch = realFetch; hooks._setRetryBaseMs(null);
await db.run("UPDATE apps SET webhook_url = NULL, webhook_secret = NULL WHERE app_id = 'tools'");
await db.run("UPDATE apps SET webhook_url = NULL, webhook_secret = NULL WHERE app_id = 'tools'");
}
}
const st = hooks.stats();
const st = hooks.stats();