Загрузка…
Загрузка…
Short-poll for low-stakes; long-poll with cursor + immediate re-arm; server holds until news or 204 timeout.
// SHORT-POLL — fine for "eventually" data (build status, low-stakes counters)
setInterval(async () => {
const r = await fetch('/api/status');
render(await r.json());
}, 5000); // ← latency you're accepting: up to 5s
// LONG-POLL — near-real-time with only fetch(). Note the cursor + immediate re-arm.
async function subscribe(cursor = 0) {
while (true) {
try {
const r = await fetch(`/api/updates?since=${cursor}`); // server HOLDS this
if (r.status === 204) continue; // server timed out → re-poll, no gap
const batch = await r.json();
for (const ev of batch.events) apply(ev);
cursor = batch.cursor; // advance so we never miss/replay
} catch {
await new Promise((res) => setTimeout(res, 1000)); // backoff on network error
}
}
}// server (long-poll) — do NOT answer until there's news or a timeout
app.get('/api/updates', async (req, res) => {
const since = Number(req.query.since);
const events = await waitForEventsSince(since, { timeoutMs: 30000 });
if (!events.length) return res.status(204).end(); // let client re-arm
res.json({ events, cursor: events.at(-1).id });
});Long-poll correctness = cursor advancement + 204 re-arm + hold timeout below proxy limits.
