Skip to content

Commit febbc84

Browse files
committed
Retry arXiv scrape on suspicious zero-paper result, surface failures distinctly
Three consecutive weekday runs (7/22-7/24) reported 0 papers despite the listing page matching today's date, versus a historical baseline of 70-150/day. A live workflow_dispatch debug run confirmed the same GitHub Actions network gets the correct page moments later, so this is a transient CDN/origin blip around the scheduled run time, not a real quiet day or an IP block. Retries the listing fetch a few times on an unexpected 0, and if it's still 0, posts a distinct warning instead of the normal calm 'no relevant papers today' message so a real failure is never silently indistinguishable from a genuinely quiet day. Also adds a descriptive User-Agent per arXiv's robots policy.
1 parent d4af4cc commit febbc84

1 file changed

Lines changed: 47 additions & 6 deletions

File tree

disk-digest.js

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,54 @@ async function savePostedIds(ids) {
8080
// Scrape the daily new-listings page for today's paper IDs, then fetch full
8181
// metadata for those IDs from the arXiv API. Returns null if the listing page
8282
// has not been updated for today yet (distinct from "no papers found").
83-
84-
async function fetchArxivPapers() {
85-
const listRes = await withRetry(() => fetch("https://arxiv.org/list/astro-ph/new"));
83+
//
84+
// arXiv's listing page is served through a multi-layer CDN (Varnish/Google
85+
// Frontend) and has occasionally been observed to briefly serve a page that
86+
// matches today's date but has an empty "New submissions" section — a
87+
// transient cache/origin blip, not a real zero-paper day (weekdays reliably
88+
// have 70+ new astro-ph submissions). We identify ourselves with a UA per
89+
// https://arxiv.org/help/robots and retry a few times before trusting a 0.
90+
91+
const FETCH_HEADERS = { "User-Agent": "disk-digest/1.0 (contact: rteague@mit.edu)" };
92+
const ZERO_IDS_RETRY_ATTEMPTS = 3;
93+
const ZERO_IDS_RETRY_DELAY_MS = 15_000;
94+
95+
async function fetchArxivListingIds() {
96+
const listRes = await withRetry(() => fetch("https://arxiv.org/list/astro-ph/new", { headers: FETCH_HEADERS }));
8697
const html = await listRes.text();
8798

8899
// Verify the listing is for today (UTC) before proceeding
89100
const now = new Date();
90101
const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
91102
const todayStr = `${now.getUTCDate()} ${MONTHS[now.getUTCMonth()]} ${now.getUTCFullYear()}`;
92-
if (!html.includes(todayStr)) return null;
103+
if (!html.includes(todayStr)) return { status: "not-updated" };
93104

94105
// The page lists new submissions, cross-lists, and replacements in that
95106
// order. Replacements are revised old papers, not new ones — drop them.
96107
const newSection = html.split(/Replacement submissions/i)[0];
97108

98109
// Extract all unique arXiv IDs from the new + cross-list sections
99110
const ids = [...new Set([...newSection.matchAll(/arXiv:(\d{4}\.\d{4,5})/g)].map(m => m[1]))];
100-
if (ids.length === 0) return [];
111+
return { status: "ok", ids };
112+
}
113+
114+
async function fetchArxivPapers() {
115+
let ids = [];
116+
for (let attempt = 1; attempt <= ZERO_IDS_RETRY_ATTEMPTS; attempt++) {
117+
const result = await fetchArxivListingIds();
118+
if (result.status === "not-updated") return null;
119+
ids = result.ids;
120+
if (ids.length > 0) break;
121+
if (attempt < ZERO_IDS_RETRY_ATTEMPTS) {
122+
console.log(` ⚠️ Listing page matched today's date but had 0 papers (attempt ${attempt}/${ZERO_IDS_RETRY_ATTEMPTS}) — retrying in ${ZERO_IDS_RETRY_DELAY_MS / 1000}s in case of a transient CDN/origin blip...`);
123+
await new Promise(r => setTimeout(r, ZERO_IDS_RETRY_DELAY_MS));
124+
}
125+
}
126+
if (ids.length === 0) return { suspiciousZero: true };
101127

102128
// Fetch full metadata (titles, abstracts, authors) for all IDs in one API call
103129
const apiUrl = `https://export.arxiv.org/api/query?id_list=${ids.join(",")}&max_results=${ids.length}`;
104-
const apiRes = await withRetry(() => fetch(apiUrl));
130+
const apiRes = await withRetry(() => fetch(apiUrl, { headers: FETCH_HEADERS }));
105131
const xml = await apiRes.text();
106132

107133
const entries = [...xml.matchAll(/<entry>([\s\S]*?)<\/entry>/g)];
@@ -273,6 +299,21 @@ async function main() {
273299
console.log(" ⚠️ arxiv.org/list/astro-ph/new is not yet updated for today. Nothing to do.");
274300
return;
275301
}
302+
if (fetched.suspiciousZero) {
303+
// The listing page matched today's date but had an empty "New submissions"
304+
// section even after retries — weekdays reliably have 70+ new astro-ph
305+
// papers, so this almost certainly means arXiv/its CDN served a broken or
306+
// stale page rather than a real zero-paper day. Surface that distinctly
307+
// instead of silently posting the calm "no relevant papers" notice, which
308+
// would look identical to a genuinely quiet day.
309+
console.log(" ❌ Still 0 papers after retries — this looks like a scrape failure, not a real zero-paper day.");
310+
await postToSlack([
311+
{ type: "header", text: { type: "plain_text", text: "🪐 Protoplanetary Disk Digest — scrape failed", emoji: true } },
312+
{ type: "section", text: { type: "mrkdwn",
313+
text: "_arxiv.org/list/astro-ph/new matched today's date but returned 0 papers, even after retries. This is very unlikely to be a real zero-paper day — the scrape probably hit a transient arXiv/CDN issue. No papers were recorded as checked, so a manual re-run today (workflow_dispatch) should pick them up — tomorrow's run will only see tomorrow's listing, not today's._" } },
314+
]);
315+
return;
316+
}
276317
console.log(` ${fetched.length} papers found on arxiv.org/list/astro-ph/new.`);
277318

278319
// Skip anything already digested on a previous day (e.g. cross-listings)

0 commit comments

Comments
 (0)