Skip to content

Crawlers: 10 s fetch, 30 s render, 30-day recheck for slow or broken targets - #442

Merged
ralyodio merged 1 commit into
masterfrom
crawl-10s-30s-30d
Nov 8, 2026
Merged

ralyodio merged 1 commit into
masterfrom
crawl-10s-30s-30d

Conversation

@ralyodio

@ralyodio ralyodio commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Fleet crawler rule (2026-11-08): third-party fetches get 10 s, headless renders 30 s, and a slow or broken target is flagged and left alone for 30 days, then rechecked once.

  • lib/crawl/policy.ts: the constants (CRAWL_FETCH_TIMEOUT_MS 10 s, TOR_FETCH_TIMEOUT_MS 30 s, CRAWL_BROWSER_TIMEOUT_MS 30 s, settle 2 s, CRAWL_RECHECK_MS 30 d) plus pure failure classification (timeout / DNS / TLS / connect / 5xx = slow_or_broken, 429 = Retry-After capped at 30 d).
  • Promote ingest: 15 s -> 10 s, the body read is now inside the budget; slow/broken feeds park 30 d instead of the 1-day backoff cap; 4xx keeps the backoff until 8 in a row.
  • Social feed autopost: 12 s -> 10 s; next_check_at/failed_at park a dead feed 30 d (4xx: daily) instead of every 15 min. Saving the config clears the flag.
  • lx feed sources: given_up gets one recheck every 30 d (5 per sweep).
  • lx sitemaps: a root fetch failure is an error, not "empty"; errors set sitemap_next_check_at +30 d and an hourly worker sweep runs the recheck.
  • Audit fetch 15 s -> 10 s (Tor budget for .onion), outreach page/PDF fetch and feed validation -> 10 s.
  • Audit render: load + bounded settle instead of networkidle; a failed render is recorded as renderError instead of an empty rendered page. Outreach render: one 30 s deadline across load, settle and scrolling.

Exempt, untouched: uptime monitors, ad link-health, own/vendor calls, heroBackfill, worker/pdf.ts and worker/frames.ts (render our own pages, already bounded).

Migration 20261108170000_crawl_recheck_30d.sql is additive and already applied to prod (9 errored sitemaps backfilled).

🤖 Generated with Claude Code

…targets

Fleet crawler policy in one module (lib/crawl/policy.ts): CRAWL_FETCH_TIMEOUT_MS
10 s (Tor keeps a separate 30 s budget), CRAWL_BROWSER_TIMEOUT_MS 30 s with a
<= 2 s bounded settle, and CRAWL_RECHECK_MS 30 days for a target that timed out,
failed DNS/TLS/connect or answered 5xx (429 honours Retry-After, capped).

- promote ingest: 15 s -> 10 s with the body inside the budget; slow/broken
  feeds park 30 days, 4xx keeps the backoff until 8 in a row, then parks.
- social feed autopost: 12 s -> 10 s; new next_check_at/failed_at park a dead
  feed 30 days (4xx: daily) instead of refetching every 15 minutes.
- lx feed sources: given_up is no longer forever; one recheck every 30 days.
- lx sitemaps: root failures are errors (not "empty"), errors get
  sitemap_next_check_at +30 days and an hourly worker sweep runs the recheck.
- audit fetch 15 s -> 10 s, outreach page/PDF fetch -> 10 s, feed validation
  -> 10 s.
- audit render: load + bounded settle instead of networkidle; a failed render
  is recorded as renderError, not an empty page. Outreach render: one 30 s
  deadline across load, settle and scrolling.

Exempt and untouched: uptime monitors, ad link-health, own/vendor services,
worker/pdf.ts and worker/frames.ts (render our own pages, already bounded).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

50 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 30 | LOW: 18

Severity Rule Location
HIGH tls-verification-disabled lib/onion.ts:50
HIGH secret-generic-credential lib/sp/platforms/facebook.ts:32
MEDIUM js-unescaped-html-sink app/(app)/dashboard/admin/email-broadcast/EmailBroadcastForm.tsx:125
MEDIUM js-unescaped-html-sink app/(app)/dashboard/projects/[id]/autoblog/articles/[articleId]/page.tsx:214
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:74
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:102
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:177
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:181
MEDIUM js-unescaped-html-sink app/c/[project]/[slug]/page.tsx:76
MEDIUM js-unescaped-html-sink app/c/[project]/page.tsx:58
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:228
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:285
MEDIUM js-unescaped-html-sink app/layout.tsx:129
MEDIUM js-open-redirect app/login/form.tsx:40
MEDIUM js-unescaped-html-sink app/r/[token]/page.tsx:164
MEDIUM js-open-redirect app/signup/form.tsx:65
MEDIUM js-unescaped-html-sink app/surveys/[slug]/invite/page.tsx:68
MEDIUM js-unescaped-html-sink components/json-ld.tsx:8
MEDIUM js-unescaped-html-sink components/pit-footer.tsx:17
MEDIUM js-unescaped-html-sink components/report/markdown-view.tsx:16
MEDIUM js-unescaped-html-sink lib/careers/page-templates.ts:198
MEDIUM js-dynamic-code-execution lib/crawl-limits.ts:67
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:41
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:324
MEDIUM redos-nested-quantifier lib/lx/articleGen.ts:100
MEDIUM redos-nested-quantifier lib/tracker/agent-gate.ts:61
MEDIUM sh-predictable-temp-path ops/selfhost/server/setup-supabase.sh:218
MEDIUM sql-template-interpolation scripts/detect-slot-themes.ts:31
MEDIUM sql-template-interpolation scripts/purge-constructed-keywords.ts:163
MEDIUM sql-template-interpolation scripts/purge-offniche-keywords.ts:124
MEDIUM js-dynamic-code-execution scripts/test-crawl-limits.mjs:14
MEDIUM js-dynamic-code-execution scripts/test-crawl-limits.mjs:24
LOW secret-generic-credential app/(marketing)/docs/autoblog-webhook/page.tsx:156
LOW secret-generic-credential lib/sealed/migrate.ts:38
LOW secret-generic-credential lib/sp/platforms/linkedin.ts:25
LOW secret-generic-api-key tests/ads-generator-agent.test.ts:160
LOW secret-generic-api-key tests/ads-generator-agent.test.ts:187
LOW js-dynamic-code-execution tests/careers-page-templates.test.ts:21
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:19
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:69
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:51
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:52
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:20
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:24
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:25
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:26
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:31
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:35
LOW secret-generic-credential tests/contract/posthog-integration.test.ts:13
LOW secret-generic-credential tests/lead-campaign.test.ts:16

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 4a2c6b3 into master Nov 8, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant