Web Crawler — Failure Scenarios¶
A crawler runs for months against a hostile, unreliable web. The themes: never lose the frontier (that's the accumulated work), never crash a worker on one bad page, survive traps and slow servers, and be resumable.
Fetcher crashes mid-download¶
- Impact: the URLs it had leased from the frontier are in-flight and unfinished.
- Detect: lease expiry / missing heartbeat.
- Contain/recover: frontier entries are leased with a timeout (like a visibility timeout); on expiry they become eligible again and another fetcher picks them up. A rare double-fetch is harmless because dedup/idempotency de-duplicate the result.
- Fetchers are stateless → just replace/restart; autoscale the pool.
Frontier node fails¶
- Impact: the URLs on that shard (a subset of hosts) are temporarily unavailable → those hosts stall.
- Detect: shard health check.
- Contain: the frontier is persisted/replicated per shard → promote a replica; other shards keep crawling (blast radius = the hosts on that one shard).
- Recover: restore from the durable log/checkpoint; never rebuild the frontier by re-crawling the web.
- This is why the frontier must be durable, not in-memory — losing it means losing months of discovery.
Seen-set / Bloom filter lost¶
- Impact: without "seen" state we'd re-enqueue already-crawled URLs → wasted work, not incorrectness.
- Contain/recover: persist/snapshot the Bloom filter and back it with a sharded KV; on restart, reload the snapshot + replay recent additions. A cold seen-set causes a temporary spike of re-fetches (dedup on the KV backing still catches most), which is tolerable but wasteful → snapshot regularly.
A crawler trap (infinite URL space)¶
- Impact: one host generates endless unique URLs (calendar, session ids, faceted nav) → the frontier fills with junk from one host; real crawling starves.
- Detect: abnormal URLs-per-host growth, parameter explosion, very deep paths.
- Contain: per-host URL budget + depth limit + parameter/pattern heuristics + session-id stripping in normalization. Blacklist pathological patterns. (See traps.)
A target server is slow / hostile (200 ms → 30 s, or returns garbage)¶
- Impact: fetch threads tie up waiting; oversized/streaming responses exhaust memory.
- Contain: per-request timeout, max page size (stream + abort oversized), redirect-chain cap, tolerant parsing (bad HTML never crashes a worker). One slow host must not stall others (its back-queue just progresses slowly).
A site rate-limits / blocks us (429 / 403)¶
- Impact: requests to that host fail.
- Detect: rising 429/403 per host.
- Contain: exponential backoff per host, honor
Retry-After, tighten that host's crawl-delay, and — if persistent — park the host and alert. Being politer is the fix; never retry-storm a host that's pushing back.
DNS resolver overload / failure¶
- Impact: fetches can't resolve hosts → throughput collapses.
- Detect: DNS latency/error spike.
- Contain: DNS cache absorbs most lookups; run redundant caching resolvers; async resolution with timeout+retry; serve stale cache entries during resolver outages rather than failing.
Object storage (page store) throttles or is unavailable¶
- Impact: can't persist fetched pages.
- Detect: write errors / S3 throttling.
- Contain: buffer/backpressure — if storage is slow, slow the fetchers (bounded in-flight); retry writes with backoff; batch/multipart uploads. Don't drop fetched content silently; apply backpressure up the pipeline.
Downstream (indexer) can't keep up¶
- Impact: the crawler produces pages faster than the indexer consumes.
- Contain: decouple via a durable queue/object store between crawler and indexer → the crawler isn't blocked by the indexer, and the indexer catches up at its own rate (queues & workers).
Full restart / deploy¶
- Impact: everything stops; must resume without re-crawling the web.
- Contain: checkpoint frontier + seen-set continuously; on restart, reload state and continue. Rolling deploys so only a fraction of fetchers restart at once; leases cover the in-flight URLs of restarting workers.
Whole-region / network-egress failure¶
- Impact: lose crawl capacity / bandwidth in a region.
- Contain: multi-region fetcher pools; shards can be re-assigned to healthy regions; the durable frontier means no discovered work is lost.
Failure-handling toolkit used here¶
leased frontier entries (redeliver on crash) · durable/replicated frontier (never lose work) ·
Bloom-filter snapshots · per-host backoff + Retry-After · per-request timeout / max page size / redirect cap
· per-host URL & depth budgets (traps) · DNS cache + redundant resolvers + stale-serve ·
backpressure to storage/indexer · checkpoint + resume · stateless fetchers (replace freely).
Priorities (say this)¶
"My durability budget goes to the frontier and seen-set — they're the accumulated crawl state; losing them means re-crawling the web, so they're persisted, replicated, and checkpointed. Individual fetches are disposable: a crashed fetcher's leased URLs simply get redelivered, and dedup makes the rare double-fetch harmless. And the whole system must survive a hostile web — timeouts, size caps, trap budgets, and per-host backoff keep one bad site from taking down the crawl."
→ Next: Interview Questions