Fix: Logger-Flush konnte ungeschriebene Zeilen verlieren (Race mit 1MB-Cap)
flushAsync nahm eine Kopie der pending-Zeilen und entfernte sie nach dem await per Index-Zaehlung (slice(snapshot.length)). Feuerte waehrend des awaits ein write() den 1MB-Buffer-Cap, der vorne Zeilen wegshiftet, war die Zaehlung desynchron und verwarf neu hinzugekommene, noch nicht geschriebene Zeilen. Jetzt: pending-Zeilen per Move uebernehmen (Buffer auf [] zuruecksetzen) statt kopieren; await-Zeit-writes laufen in einen frischen Buffer. Bei Schreibfehler werden die Zeilen wieder vorn eingereiht und der Cap erneut angewandt.
This commit is contained in:
parent
272a41a4a7
commit
4432fa25e8
@ -183,7 +183,14 @@ async function flushAsync(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flushInFlight = true;
|
flushInFlight = true;
|
||||||
const linesSnapshot = pendingLines.slice();
|
// Move (not copy) the pending lines out and take ownership. A concurrent write()
|
||||||
|
// during the await below pushes new lines AND can trim the 1MB cap from the FRONT
|
||||||
|
// of pendingLines; the old count-based removal (pendingLines.slice(snapshot.length))
|
||||||
|
// then sliced off the wrong lines and dropped unwritten ones. Resetting the buffer
|
||||||
|
// here means await-time writes queue independently and nothing desyncs.
|
||||||
|
const linesSnapshot = pendingLines;
|
||||||
|
pendingLines = [];
|
||||||
|
pendingChars = 0;
|
||||||
const chunk = linesSnapshot.join("");
|
const chunk = linesSnapshot.join("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -200,9 +207,19 @@ async function flushAsync(): Promise<void> {
|
|||||||
} else if (!primary.ok) {
|
} else if (!primary.ok) {
|
||||||
writeStderr(`LOGGER write failed: ${primary.errorText}\n`);
|
writeStderr(`LOGGER write failed: ${primary.errorText}\n`);
|
||||||
}
|
}
|
||||||
if (wroteAny) {
|
if (!wroteAny) {
|
||||||
pendingLines = pendingLines.slice(linesSnapshot.length);
|
// Write failed: requeue the unwritten lines AHEAD of anything that arrived
|
||||||
pendingChars = Math.max(0, pendingChars - chunk.length);
|
// during the await (preserve order), then re-apply the buffer cap so a
|
||||||
|
// persistent write failure cannot grow the buffer without bound.
|
||||||
|
pendingLines = linesSnapshot.concat(pendingLines);
|
||||||
|
pendingChars += chunk.length;
|
||||||
|
while (pendingChars > LOG_BUFFER_LIMIT_CHARS && pendingLines.length > 1) {
|
||||||
|
const removed = pendingLines.shift();
|
||||||
|
if (!removed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pendingChars = Math.max(0, pendingChars - removed.length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
flushInFlight = false;
|
flushInFlight = false;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user