mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
test(ql3): bound provider convergence retries
This commit is contained in:
@@ -1105,11 +1105,24 @@ request.on('timeout',()=>request.destroy(Object.assign(new Error('timeout'),{cod
|
|||||||
return evidence;
|
return evidence;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retryProviderEvidence(read, pause = undefined) {
|
async function retryProviderEvidence(read, options = {}) {
|
||||||
assert.equal(typeof read, 'function');
|
assert.equal(typeof read, 'function');
|
||||||
assert.ok(pause === undefined || typeof pause === 'function');
|
assert.equal(typeof options, 'object');
|
||||||
|
assert.ok(options !== null && !Array.isArray(options));
|
||||||
|
const pause =
|
||||||
|
options.pause ??
|
||||||
|
((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
|
||||||
|
const now = options.now ?? Date.now;
|
||||||
|
const intervalMs = options.intervalMs ?? 1_000;
|
||||||
|
const timeoutMs = options.timeoutMs ?? 3 * 60_000;
|
||||||
|
const maxAttempts = options.maxAttempts ?? 16;
|
||||||
|
assert.equal(typeof pause, 'function');
|
||||||
|
assert.equal(typeof now, 'function');
|
||||||
|
assert.ok(Number.isSafeInteger(intervalMs) && intervalMs >= 0);
|
||||||
|
assert.ok(Number.isSafeInteger(timeoutMs) && timeoutMs > 0);
|
||||||
|
assert.ok(Number.isSafeInteger(maxAttempts) && maxAttempts > 0);
|
||||||
|
const startedAt = now();
|
||||||
let lastError;
|
let lastError;
|
||||||
const maxAttempts = 8;
|
|
||||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||||
try {
|
try {
|
||||||
return await read();
|
return await read();
|
||||||
@@ -1119,13 +1132,12 @@ async function retryProviderEvidence(read, pause = undefined) {
|
|||||||
!/\b(?:ECONNREFUSED|ECONNRESET|ETIMEDOUT|TIMEOUT)\b/.test(
|
!/\b(?:ECONNREFUSED|ECONNRESET|ETIMEDOUT|TIMEOUT)\b/.test(
|
||||||
error instanceof Error ? error.message : String(error),
|
error instanceof Error ? error.message : String(error),
|
||||||
) ||
|
) ||
|
||||||
attempt === maxAttempts
|
attempt === maxAttempts ||
|
||||||
|
now() - startedAt >= timeoutMs
|
||||||
) {
|
) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
await (
|
await pause(intervalMs);
|
||||||
pause ?? (() => new Promise((resolve) => setTimeout(resolve, 1_000)))
|
|
||||||
)();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw lastError;
|
throw lastError;
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ test('retries only bounded transient provider evidence failures', async () => {
|
|||||||
if (attempts < 3) throw new Error('{"code":"ECONNREFUSED"}');
|
if (attempts < 3) throw new Error('{"code":"ECONNREFUSED"}');
|
||||||
return { requestCount: 1 };
|
return { requestCount: 1 };
|
||||||
},
|
},
|
||||||
async () => {},
|
{ pause: async () => {} },
|
||||||
);
|
);
|
||||||
assert.deepEqual(evidence, { requestCount: 1 });
|
assert.deepEqual(evidence, { requestCount: 1 });
|
||||||
assert.equal(attempts, 3);
|
assert.equal(attempts, 3);
|
||||||
@@ -386,7 +386,7 @@ test('retries only bounded transient provider evidence failures', async () => {
|
|||||||
async () => {
|
async () => {
|
||||||
throw new Error('invalid evidence schema');
|
throw new Error('invalid evidence schema');
|
||||||
},
|
},
|
||||||
async () => {},
|
{ pause: async () => {} },
|
||||||
),
|
),
|
||||||
/invalid evidence schema/,
|
/invalid evidence schema/,
|
||||||
);
|
);
|
||||||
@@ -398,11 +398,33 @@ test('retries only bounded transient provider evidence failures', async () => {
|
|||||||
attempts += 1;
|
attempts += 1;
|
||||||
throw new Error('{"code":"ECONNREFUSED"}');
|
throw new Error('{"code":"ECONNREFUSED"}');
|
||||||
},
|
},
|
||||||
async () => {},
|
{ maxAttempts: 8, pause: async () => {} },
|
||||||
),
|
),
|
||||||
/ECONNREFUSED/,
|
/ECONNREFUSED/,
|
||||||
);
|
);
|
||||||
assert.equal(attempts, 8);
|
assert.equal(attempts, 8);
|
||||||
|
|
||||||
|
attempts = 0;
|
||||||
|
let elapsedMs = 0;
|
||||||
|
await assert.rejects(
|
||||||
|
retryProviderEvidence(
|
||||||
|
async () => {
|
||||||
|
attempts += 1;
|
||||||
|
throw new Error('{"code":"ETIMEDOUT"}');
|
||||||
|
},
|
||||||
|
{
|
||||||
|
intervalMs: 1_000,
|
||||||
|
maxAttempts: 100,
|
||||||
|
now: () => elapsedMs,
|
||||||
|
pause: async (delayMs) => {
|
||||||
|
elapsedMs += delayMs;
|
||||||
|
},
|
||||||
|
timeoutMs: 3_000,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
/ETIMEDOUT/,
|
||||||
|
);
|
||||||
|
assert.equal(attempts, 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('provider fixture logs only generation and authorization decision', () => {
|
test('provider fixture logs only generation and authorization decision', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user