Commit e0ff1a2d by luoqi

fix(meyer): preserve request counts after status write failures

parent 7fd8e892
Pipeline #3838 failed in 0 seconds
...@@ -74,7 +74,9 @@ export async function runMeyerTick(config: MeyerConfig, sourceFor: (c: MeyerConf ...@@ -74,7 +74,9 @@ export async function runMeyerTick(config: MeyerConfig, sourceFor: (c: MeyerConf
retryFailed += result.failed + result.analysisFailed; retryFailed += result.failed + result.analysisFailed;
} catch { } catch {
retryFailed++; retryFailed++;
await pending.write(key, { ...value, attempts: value.attempts + 1, // collector 可能已持久化请求次数后才在写运行摘要时失败;不能回写旧次数。
const retained = await pending.read<PendingImage>(key) ?? value;
await pending.write(key, { ...retained, attempts: retained.attempts + 1,
nextRetryAt: new Date(now + 3600000).toISOString() }); nextRetryAt: new Date(now + 3600000).toISOString() });
} }
} }
......
...@@ -115,4 +115,24 @@ describe('Meyer analysis retry policy', () => { ...@@ -115,4 +115,24 @@ describe('Meyer analysis retry policy', () => {
expect(s.source.symptom).not.toHaveBeenCalled(); expect(s.source.symptom).not.toHaveBeenCalled();
expect(s.sink.apply).toHaveBeenCalledTimes(1); expect(s.sink.apply).toHaveBeenCalledTimes(1);
}); });
test('a later status-write failure cannot roll back durable analysis attempts in scheduler recovery', async () => {
const s = setup(); s.config.maxAnalysisAttempts = 1;
await s.store.write('cursor', { through: chinaTime(created + 2 * 3600000) });
await s.pending.write(s.key, { scope: s.config.scopes[0], image: meyerImage(), attempts: 1,
analysisAttempts: 0, nextRetryAt: new Date(created).toISOString() });
const write = s.store.write.bind(s.store);
const spy = jest.spyOn(s.store, 'write').mockImplementation(async (key, value) => {
if (key === 'last-run') throw Error('status file unavailable');
return write(key, value);
});
const result = await runMeyerTick(s.config, () => s.source, s.store, codes, s.sink, created + 2 * 3600000);
spy.mockRestore();
expect(result.retryFailed).toBe(1);
expect(await s.pending.read(s.key)).toMatchObject({ analysisAttempts: 1, autoRetry: false, reason: 'analysis_exhausted' });
expect(s.source.symptom).toHaveBeenCalledTimes(1);
await s.store.write('cursor', { through: chinaTime(created + 4 * 3600000) });
const factory = jest.fn(() => s.source);
await runMeyerTick(s.config, factory, s.store, codes, s.sink, created + 4 * 3600000);
expect(factory).not.toHaveBeenCalled();
});
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment