diff --git a/src/background/diagnostic-log-store.ts b/src/background/diagnostic-log-store.ts index 1d586d1..fcb7718 100644 --- a/src/background/diagnostic-log-store.ts +++ b/src/background/diagnostic-log-store.ts @@ -6,17 +6,25 @@ const MAX_RECENT_LOGS = 300; type DiagnosticStoreStorage = Pick; export class DiagnosticLogStore { + private appendChain: Promise = Promise.resolve(); + constructor(private readonly storageManager: DiagnosticStoreStorage = storage) {} async append(entry: DiagnosticLogEntry): Promise { - const recent = await this.getRecent(); - const next = [...recent, entry]; + const runAppend = async () => { + const recent = await this.getRecent(); + const next = [...recent, entry]; - if (next.length > MAX_RECENT_LOGS) { - next.splice(0, next.length - MAX_RECENT_LOGS); - } + if (next.length > MAX_RECENT_LOGS) { + next.splice(0, next.length - MAX_RECENT_LOGS); + } - await this.storageManager.set(DIAGNOSTIC_STORAGE_KEYS.RECENT_LOGS, next); + await this.storageManager.set(DIAGNOSTIC_STORAGE_KEYS.RECENT_LOGS, next); + }; + + const appendPromise = this.appendChain.then(runAppend, runAppend); + this.appendChain = appendPromise.catch(() => undefined); + return appendPromise; } async getRecent(): Promise { diff --git a/tests/unit/diagnostic-log-store.test.ts b/tests/unit/diagnostic-log-store.test.ts index d95789f..07a391b 100644 --- a/tests/unit/diagnostic-log-store.test.ts +++ b/tests/unit/diagnostic-log-store.test.ts @@ -54,6 +54,33 @@ describe('DiagnosticLogStore', () => { expect(logs.at(-1)?.id).toBe('log-304'); }); + it('does not lose logs when append is called concurrently', async () => { + let currentLogs: DiagnosticLogEntry[] = []; + + const concurrentStorage = { + get: vi.fn(async () => { + const snapshot = [...currentLogs]; + await new Promise((resolve) => setTimeout(resolve, 0)); + return snapshot; + }), + set: vi.fn(async (_key: string, value: DiagnosticLogEntry[]) => { + currentLogs = value; + }), + remove: vi.fn(async () => {}), + }; + + const store = new DiagnosticLogStore(concurrentStorage as any); + + await Promise.all([ + store.append({ id: 'log-a', level: 'INFO', message: 'A' }), + store.append({ id: 'log-b', level: 'INFO', message: 'B' }), + ]); + + expect(currentLogs).toHaveLength(2); + expect(currentLogs.map((item) => item.id)).toEqual(['log-a', 'log-b']); + }); + + it('clears the buffer without touching unrelated keys', async () => { const store = new DiagnosticLogStore(new StorageManager());