fix(quick-save): Drain-Trailing-Re-Run gegen verworfene onChanged waehrend laufendem Drain (Latenz, kein Verlust)

This commit is contained in:
2026-06-14 14:29:47 +02:00
parent 43403bc755
commit 767c7c80aa
+12 -8
View File
@@ -233,19 +233,19 @@ function bindGlobalEvents() {
});
}
// ---- LIVE-SYNC (Quick-Save aus dem Background) ----
// Ein Quick-Save schreibt boards im Background. Ein offener Tab muss das sehen,
// sonst ueberschreibt er den Eintrag beim naechsten eigenen Save (QS-03).
// Drained die Quick-Save-Queue in die Inbox. Die SEITE ist die einzige Schreiberin von 'boards';
// der Background-Worker haengt nur an 'quicksave_pending' an. Dadurch koennen sich Worker und Seite
// nicht im boards-Array gegenseitig ueberschreiben (Datensicherheit, Phase-4-Review-Blocker 2b).
// ---- QUICK-SAVE PENDING-QUEUE ----
// Der Background-Worker haengt Quick-Saves an den eigenen Store-Key 'quicksave_pending' an (er
// schreibt NIE boards). Diese Seite ist die einzige boards-Schreiberin und drained die Queue in die
// Inbox. Getrennte Schreib-Domaenen -> Worker und Seite koennen sich nicht im boards-Array
// gegenseitig ueberschreiben (Datensicherheit, Phase-4-Review-Blocker 2b).
let _drainBusy = false;
let _drainQueued = false; // ein waehrend eines laufenden Drains angefragter Drain wird nachgeholt
async function drainQuickSavePending() {
if (_drainBusy) return; // Re-Entry-Schutz (init + onChanged koennten ueberlappen)
if (_drainBusy) { _drainQueued = true; return; }
_drainBusy = true;
try {
const pending = await Store.get('quicksave_pending');
if (!Array.isArray(pending) || pending.length === 0) return;
if (Array.isArray(pending) && pending.length > 0) {
const drained = pending.slice();
const drainedIds = new Set(drained.map(e => e && e.id).filter(Boolean));
const inbox = await ensureInboxBoard(); // legt die Inbox an, falls noetig; gibt das Board zurueck
@@ -261,11 +261,15 @@ async function drainQuickSavePending() {
await Store.set('quicksave_pending', remaining);
// Render nur, wenn gerade KEIN Drag laeuft (renderBoards->replaceChildren wuerde ihn abreissen).
if (!document.querySelector('.board.dragging, .bm-item.dragging-source')) renderBoards();
}
} catch (e) {
console.error('Quick-Save-Drain fehlgeschlagen:', e && e.message);
} finally {
_drainBusy = false;
}
// Kam waehrend des Drains ein weiterer Quick-Save an (onChanged wurde durch _drainBusy verworfen),
// jetzt nachholen. Der Eintrag war sicher in der Queue, nur noch nicht eingelesen.
if (_drainQueued) { _drainQueued = false; drainQuickSavePending(); }
}
// Live-Sync (QS-03): ein offener NewTab drained die Queue, sobald der Worker etwas anhaengt.