mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-23 14:36:41 +00:00
fix database persistence during container shutdown (#1104)
This commit is contained in:
@@ -163,8 +163,4 @@ else
|
||||
echo "Warning: package.json not found"
|
||||
fi
|
||||
|
||||
node dist/backend/backend/starter.js
|
||||
|
||||
echo "All services started"
|
||||
|
||||
tail -f /dev/null
|
||||
exec node dist/backend/backend/starter.js
|
||||
|
||||
@@ -38,4 +38,28 @@ describe("DatabaseSaveTrigger", () => {
|
||||
expect(DatabaseSaveTrigger.isDirty).toBe(false);
|
||||
expect(DatabaseSaveTrigger.getStatus().pendingSave).toBe(false);
|
||||
});
|
||||
|
||||
it("queues a force save behind an in-flight save", async () => {
|
||||
let finishFirstSave: (() => void) | undefined;
|
||||
const firstSave = new Promise<void>((resolve) => {
|
||||
finishFirstSave = resolve;
|
||||
});
|
||||
const save = vi
|
||||
.fn<() => Promise<void>>()
|
||||
.mockReturnValueOnce(firstSave)
|
||||
.mockResolvedValueOnce(undefined);
|
||||
DatabaseSaveTrigger.initialize(save);
|
||||
|
||||
const first = DatabaseSaveTrigger.forceSave("first_write");
|
||||
await vi.waitFor(() => expect(save).toHaveBeenCalledTimes(1));
|
||||
|
||||
const second = DatabaseSaveTrigger.forceSave("sso_provider_write");
|
||||
expect(save).toHaveBeenCalledTimes(1);
|
||||
|
||||
finishFirstSave?.();
|
||||
await Promise.all([first, second]);
|
||||
|
||||
expect(save).toHaveBeenCalledTimes(2);
|
||||
expect(DatabaseSaveTrigger.getStatus().pendingSave).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ export class DatabaseSaveTrigger {
|
||||
private static saveFunction: (() => Promise<void>) | null = null;
|
||||
private static isInitialized = false;
|
||||
private static pendingSave = false;
|
||||
private static activeSave: Promise<void> | null = null;
|
||||
private static saveTimeout: NodeJS.Timeout | null = null;
|
||||
private static _dirty = false;
|
||||
|
||||
@@ -38,14 +39,10 @@ export class DatabaseSaveTrigger {
|
||||
}
|
||||
|
||||
this.saveTimeout = setTimeout(async () => {
|
||||
if (this.pendingSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pendingSave = true;
|
||||
this.saveTimeout = null;
|
||||
|
||||
try {
|
||||
await this.saveFunction!();
|
||||
await this.runSave();
|
||||
this._dirty = false;
|
||||
} catch (error) {
|
||||
databaseLogger.error("Database save failed", error, {
|
||||
@@ -53,8 +50,6 @@ export class DatabaseSaveTrigger {
|
||||
reason,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
});
|
||||
} finally {
|
||||
this.pendingSave = false;
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
@@ -76,14 +71,9 @@ export class DatabaseSaveTrigger {
|
||||
this.saveTimeout = null;
|
||||
}
|
||||
|
||||
if (this.pendingSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pendingSave = true;
|
||||
|
||||
try {
|
||||
await this.saveFunction();
|
||||
await this.runSave();
|
||||
this._dirty = false;
|
||||
} catch (error) {
|
||||
databaseLogger.error("Database force save failed", error, {
|
||||
operation: "db_save_trigger_force_failed",
|
||||
@@ -91,8 +81,29 @@ export class DatabaseSaveTrigger {
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static async runSave(): Promise<void> {
|
||||
while (this.activeSave) {
|
||||
try {
|
||||
await this.activeSave;
|
||||
} catch {
|
||||
// The queued save must still run after an earlier save failed.
|
||||
}
|
||||
}
|
||||
|
||||
const save = Promise.resolve().then(() => this.saveFunction!());
|
||||
this.activeSave = save;
|
||||
this.pendingSave = true;
|
||||
|
||||
try {
|
||||
await save;
|
||||
} finally {
|
||||
this.pendingSave = false;
|
||||
if (this.activeSave === save) {
|
||||
this.activeSave = null;
|
||||
this.pendingSave = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +126,7 @@ export class DatabaseSaveTrigger {
|
||||
}
|
||||
|
||||
this.pendingSave = false;
|
||||
this.activeSave = null;
|
||||
this.isInitialized = false;
|
||||
this.saveFunction = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user