Workers P2: Feed-Stillstand bei dichten Ereignissen behoben (Sprung hinter die Spitze)
Der Dienst liefert bei events(after) die ältesten pageLimit Einträge ab after - 5 s. Mit mehr als 200 Einträgen im Fenster kam mit after = jüngster ts immer dieselbe, schon bekannte Seite und das Neuere nie an. Eine volle Seite ohne neues Ereignis setzt jetzt eine Abrufmarke hinter die Spitze (cursor + 5 s, bei erneutem Stillstand + 1 ms), die über Runden hinweg gilt. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0bfad0ae0b
commit
67df2fd902
2 files changed
+101
-4
No files matched your search
+24
-4
@@ -5,6 +5,8 @@
|
||||
import { takeNewEvents, latestTs, needsStateRefresh } from './workersEvents.js'
|
||||
|
||||
const EPOCH = '1970-01-01T00:00:00.000Z'
|
||||
// Der Dienst liefert bei events(after) alle Einträge ab after - 5 s (P1 buildEvents), die ältesten pageLimit Stück
|
||||
const OVERLAP_MS = 5000
|
||||
const noop = () => {}
|
||||
|
||||
const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v)
|
||||
@@ -24,6 +26,7 @@ export function createFeedController({
|
||||
let cursor = null // null bis der erste Zustand da ist; danach der jüngste gesehene Zeitstempel
|
||||
let historyMs = NaN // lastEventTs des ersten Zustands: Ereignisse bis dahin sind Vorgeschichte
|
||||
let seen = new Set()
|
||||
let resume = null // Abrufmarke nach einer vollen Seite ohne Neues: der nächste Abruf fragt ab hier statt ab cursor
|
||||
let stateAgain = false // refreshState() kam während eines laufenden Zustand-Abrufs
|
||||
let reported = null // zuletzt gemeldete Fehlermeldung (null = kein Fehler)
|
||||
const timer = { state: null, events: null }
|
||||
@@ -113,20 +116,36 @@ export function createFeedController({
|
||||
return !Number.isNaN(historyMs) && Date.parse(e.ts) <= historyMs
|
||||
}
|
||||
|
||||
// Holt Seiten, solange sie voll sind (höchstens maxPages); wirft nie, ein Fehler steht im Ergebnis
|
||||
// Zeitstempel hinter der bisher gesehenen Spitze: die Marke after, bei der der Dienst (ab after - 5 s) wieder ab dem
|
||||
// jüngsten gesehenen Eintrag liefert; strict: ab 1 ms danach
|
||||
function skipTo(strict) {
|
||||
return new Date(Date.parse(cursor) + OVERLAP_MS + (strict ? 1 : 0)).toISOString()
|
||||
}
|
||||
|
||||
// Holt Seiten, solange sie voll sind (höchstens maxPages); wirft nie, ein Fehler steht im Ergebnis.
|
||||
// Stillstand-Schutz: Der Dienst liefert die ältesten pageLimit Einträge ab after - 5 s. Liegen mehr als pageLimit
|
||||
// Einträge im Fenster vor cursor, bestünde eine volle Seite nur aus schon bekannten, und mit after = cursor käme
|
||||
// immer dieselbe Seite (das Neuere käme nie an). Eine volle Seite ohne ein einziges neues Ereignis
|
||||
// setzt darum `resume` hinter die Spitze: after = cursor + 5 s fragt ab cursor (Doppelte fängt takeNewEvents ab).
|
||||
// Bleibt auch diese Seite voll und ohne Neues (pageLimit Einträge mit demselben ts), geht es ab cursor + 1 ms weiter.
|
||||
// `resume` gilt über die Runde hinaus, bis eine Seite Neues bringt oder nicht voll ist.
|
||||
async function fetchRound(myGen) {
|
||||
const fresh = []
|
||||
let failed = null
|
||||
try {
|
||||
for (let page = 0; page < maxPages; page += 1) {
|
||||
const res = await api.events(cursor, pageLimit)
|
||||
const jumped = resume !== null
|
||||
const res = await api.events(jumped ? resume : cursor, pageLimit)
|
||||
if (myGen !== gen) break
|
||||
const list = isRecord(res) && Array.isArray(res.events) ? res.events : []
|
||||
for (const e of takeNewEvents(seen, list)) {
|
||||
const unseen = takeNewEvents(seen, list)
|
||||
for (const e of unseen) {
|
||||
if (!isHistory(e)) fresh.push(e)
|
||||
}
|
||||
cursor = latestTs(list, cursor)
|
||||
if (list.length < pageLimit) break
|
||||
const full = list.length >= pageLimit
|
||||
resume = full && unseen.length === 0 ? skipTo(jumped) : null
|
||||
if (!full) break
|
||||
}
|
||||
} catch (err) {
|
||||
failed = err
|
||||
@@ -176,6 +195,7 @@ export function createFeedController({
|
||||
cursor = null
|
||||
historyMs = NaN
|
||||
seen = new Set()
|
||||
resume = null
|
||||
stateAgain = false
|
||||
reported = null
|
||||
failure.state = null
|
||||
|
||||
Reference in new issue
Block a user