v0.5.110: stop carrying stale live badges; probe live status in local serve.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
voson
2026-07-30 01:11:13 +08:00
co-authored by Cursor
parent d6212169af
commit fe1b13b7c1
10 changed files with 125 additions and 56 deletions
+34 -36
View File
@@ -15,12 +15,10 @@
* the SSR pace chunks: roomStore.roomInfo.room.status (2 live / 4 offline);
* the embedded web_rid must match the requested one.
*
* Soft-fail everywhere: douyin blocks from datacenter IPs are expected. When a
* single probe fails, the streamer carries over the last known is_live from
* data.json / the previous (stale) cache entry with `stale: true`; when every
* probe fails the stale cache entry is served wholesale (X-Live-Cache:
* stale-override), or an empty payload when nothing was ever cached
* (X-Live-Cache: error). The handler never throws a 500 for probe failures.
* Soft-fail everywhere: douyin blocks from datacenter IPs are expected. A
* failed probe is reported as offline with `stale: true`; a stale positive is
* never carried over because the live badge must only reflect a successful
* current probe. The handler never throws a 500 for probe failures.
*
* Named exports double as the local test surface; the Pages runtime only
* routes onRequest* handlers.
@@ -292,6 +290,23 @@ function emptyPayload() {
return { probed_at: new Date().toISOString(), ttl: FRESH_TTL_S, streamers: {} };
}
/** Failed probes must never preserve a stale live badge. */
function staleOfflinePayload(source) {
const streamers = {};
const previous =
source && source.streamers && typeof source.streamers === "object"
? source.streamers
: {};
for (const id of Object.keys(previous)) {
streamers[id] = { is_live: false, stale: true };
}
return {
probed_at: (source && source.probed_at) || new Date().toISOString(),
ttl: FRESH_TTL_S,
streamers,
};
}
async function putCache(body) {
const cached = new Response(JSON.stringify(body), {
headers: {
@@ -324,17 +339,12 @@ async function probeFresh(requestUrl, cachedData) {
}
if (!targets.length) {
if (cachedData) return { body: cachedData, cacheState: "stale-override" };
if (cachedData) {
return { body: staleOfflinePayload(cachedData), cacheState: "stale-override" };
}
return { body: emptyPayload(), cacheState: "error" };
}
const seeded = seedLiveFromPayload(dataPayload);
const cachedStreamers =
cachedData && cachedData.streamers && typeof cachedData.streamers === "object"
? cachedData.streamers
: {};
// Prefer previous edge cache over the daily snapshot when both exist.
const staleStreamers = { ...seeded, ...cachedStreamers };
const probed = await probeAll(targets);
const streamers = {};
@@ -346,31 +356,19 @@ async function probeFresh(requestUrl, cachedData) {
freshCount += 1;
continue;
}
// Per-streamer soft-fail: carry over the last known state, marked stale.
const prev = staleStreamers[t.id];
if (prev && typeof prev.is_live === "boolean") {
streamers[t.id] = { is_live: prev.is_live, stale: true };
}
// Unknown is not live: never carry a stale positive badge forward.
streamers[t.id] = { is_live: false, stale: true };
}
if (freshCount === 0) {
// Total probe failure (e.g. douyin blocking this colo): serve the stale
// snapshot if one exists, otherwise an explicitly empty payload.
if (cachedData) return { body: cachedData, cacheState: "stale-override" };
if (Object.keys(seeded).length) {
const body = {
probed_at: new Date().toISOString(),
ttl: FRESH_TTL_S,
streamers: Object.fromEntries(
Object.entries(seeded).map(([id, cell]) => [
id,
{ is_live: cell.is_live, stale: true },
])
),
};
return { body, cacheState: "stale-override" };
}
return { body: emptyPayload(), cacheState: "error" };
// Total probe failure (e.g. douyin blocking this colo): keep the target
// shape but suppress every unconfirmed live badge.
const body = {
probed_at: new Date().toISOString(),
ttl: FRESH_TTL_S,
streamers,
};
return { body, cacheState: "stale-override" };
}
const body = { probed_at: new Date().toISOString(), ttl: FRESH_TTL_S, streamers };