fix: memory leak hunting and reconnecting on data error

This commit is contained in:
2026-05-18 19:37:30 +02:00
parent dea114aed0
commit 0152ed9dd2
5 changed files with 148 additions and 60 deletions

View File

@@ -41,7 +41,14 @@ const RETRYABLE_SAVE_ERROR_CODES = new Set([
'EBUSY'
]);
let saveQueue: Promise<void> = Promise.resolve();
interface PendingSaveWaiter {
reject: (error: unknown) => void;
resolve: () => void;
}
let pendingSaveSnapshot: Buffer | null = null;
let pendingSaveWaiters: PendingSaveWaiter[] = [];
let saveInProgress = false;
function wait(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
@@ -146,16 +153,51 @@ async function writeDatabaseSnapshot(snapshot: Buffer): Promise<void> {
}
}
function settleSaveWaiters(waiters: PendingSaveWaiter[], error?: unknown): void {
for (const waiter of waiters) {
if (error === undefined) {
waiter.resolve();
} else {
waiter.reject(error);
}
}
}
async function drainDatabaseSaveQueue(): Promise<void> {
if (saveInProgress) {
return;
}
saveInProgress = true;
try {
while (pendingSaveSnapshot) {
const snapshot = pendingSaveSnapshot;
const waiters = pendingSaveWaiters;
pendingSaveSnapshot = null;
pendingSaveWaiters = [];
try {
await writeDatabaseSnapshot(snapshot);
settleSaveWaiters(waiters);
} catch (error) {
settleSaveWaiters(waiters, error);
}
}
} finally {
saveInProgress = false;
}
}
async function atomicSave(data: Uint8Array): Promise<void> {
const snapshot = Buffer.from(data);
const saveTask = saveQueue.then(
() => writeDatabaseSnapshot(snapshot),
() => writeDatabaseSnapshot(snapshot)
);
saveQueue = saveTask.catch(() => {});
return saveTask;
return new Promise<void>((resolve, reject) => {
pendingSaveSnapshot = snapshot;
pendingSaveWaiters.push({ resolve, reject });
void drainDatabaseSaveQueue();
});
}
export async function initializeDatabase(): Promise<void> {