Commit 277e6ba
Believe a 429 once for the whole host, instead of once per feed
Reported as the crawler being slow again: 5,000 feeds/hour down to 2,000. It was
neither the database nor a knob, and the diagnostic order in the notes settled
that in three minutes — an empty write transaction measured 0.39s (the old
saturation was 29-300s), and the poller's own `started` event showed all four
tuning variables already correct.
The live log said it instead. 130 of 136 feed events in five minutes were
`www.reddit.com`, and 106 of those were http-429.
**A bulk import put 50,099 reddit feeds in the directory** — 30,000 on 08-28 and
19,999 on 08-27, two submissions, which is exactly when throughput halved.
49,174 of them were due at once: 41% of the entire due queue on a single
hostname. Over one hour, reddit took 1,074 crawl attempts and was refused 1,015
times, while the whole rest of the directory got 218. The crawler had not slowed
down. It was spending 84% of itself being told to go away, and had read 650 of
those 50,099 feeds successfully in 36 hours of trying.
Two things combine to make one host able to do that, and neither is wrong on its
own. A host's feeds are crawled strictly in series — that is the politeness
guarantee. And `spreadHosts` deliberately lifts its per-host cap rather than
under-fill a batch, because the alternative throttles a legitimate bulk import
to eight feeds a tick. So when the due set genuinely is one host, one worker
gets most of a 900-feed batch on that host and walks it into the same rate limit
nine hundred times.
**The fix is to stop asking.** A 429 is a fact about the host, not about the feed
that happened to be at the front of its queue, so the worker now believes it
once and leaves. The rest of that host's queue is put back rather than walked.
Three things that decide whether this is right:
* **The held-back feeds are not blamed.** `markThrottled` already exists so a
rate limit is not recorded as feed health — ten consecutive failures marks a
feed dead, so counting 429s against feeds would retire a whole platform for
our own crawl rate. `markHostThrottled` extends that to feeds we did not
even send a request for, where there is even less to judge.
* **They come back spread across an hour, not at one instant.** Handing a
thousand held-back feeds a single timestamp just moves the pile-up one
interval into the future, where it walks into the same wall together.
* **It is bucketed by minute, not one statement per feed.** This database gives
the cluster one writer, and a batch of nine hundred statements holds it long
enough to push the jobs behind it past their deadline — the failure
`TURSO_QUEUE_GROUP_STATEMENTS` was lowered to 10 to avoid. Bucketing makes
the statement count a property of the window (~60) rather than of the queue.
A 404 still walks the queue to the end: that is evidence about one feed and says
nothing about the host.
`crawlDue` gained a `crawl` option so a whole batch can be driven without the
network — the throttle path only exists *across* a host's queue, so it was not
reachable from `crawlFeed`'s tests at all. The tick summary gains `throttled`,
which is what distinguishes a slow tick that was one publisher rate-limiting us
from the crawler struggling; `ms` alone cannot tell those apart.
Also done, in production rather than in code: the 50,099 reddit feeds were
rescheduled across fourteen days, taking that host from 49,174 feeds due at once
to ~145 an hour. Nothing was deleted and the update only ever pushed schedules
out. Whether a directory that describes itself as the small web rather than the
platforms should carry 50k subreddits at all is a separate question, and not one
to answer by deleting someone's upload.
Suite green: 1,206 tests, 0 failures across 11 packages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gV7AyoWsiihaakh7RYZbP1 parent a972f07 commit 277e6ba
4 files changed
Lines changed: 353 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
289 | 289 | | |
290 | 290 | | |
291 | 291 | | |
292 | | - | |
| 292 | + | |
293 | 293 | | |
294 | 294 | | |
295 | 295 | | |
| |||
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
312 | 318 | | |
313 | 319 | | |
314 | 320 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3022 | 3022 | | |
3023 | 3023 | | |
3024 | 3024 | | |
| 3025 | + | |
| 3026 | + | |
| 3027 | + | |
| 3028 | + | |
| 3029 | + | |
| 3030 | + | |
| 3031 | + | |
| 3032 | + | |
| 3033 | + | |
| 3034 | + | |
| 3035 | + | |
| 3036 | + | |
| 3037 | + | |
| 3038 | + | |
| 3039 | + | |
| 3040 | + | |
| 3041 | + | |
| 3042 | + | |
| 3043 | + | |
| 3044 | + | |
| 3045 | + | |
| 3046 | + | |
| 3047 | + | |
| 3048 | + | |
| 3049 | + | |
| 3050 | + | |
| 3051 | + | |
| 3052 | + | |
| 3053 | + | |
| 3054 | + | |
| 3055 | + | |
| 3056 | + | |
| 3057 | + | |
| 3058 | + | |
| 3059 | + | |
| 3060 | + | |
| 3061 | + | |
| 3062 | + | |
| 3063 | + | |
| 3064 | + | |
| 3065 | + | |
| 3066 | + | |
| 3067 | + | |
| 3068 | + | |
| 3069 | + | |
| 3070 | + | |
| 3071 | + | |
| 3072 | + | |
| 3073 | + | |
| 3074 | + | |
| 3075 | + | |
| 3076 | + | |
| 3077 | + | |
| 3078 | + | |
| 3079 | + | |
| 3080 | + | |
| 3081 | + | |
| 3082 | + | |
| 3083 | + | |
| 3084 | + | |
| 3085 | + | |
| 3086 | + | |
| 3087 | + | |
| 3088 | + | |
3025 | 3089 | | |
3026 | 3090 | | |
3027 | 3091 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
231 | | - | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
232 | 240 | | |
233 | 241 | | |
234 | 242 | | |
| |||
575 | 583 | | |
576 | 584 | | |
577 | 585 | | |
578 | | - | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
579 | 589 | | |
580 | 590 | | |
581 | 591 | | |
| |||
604 | 614 | | |
605 | 615 | | |
606 | 616 | | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
607 | 620 | | |
608 | 621 | | |
609 | 622 | | |
| |||
612 | 625 | | |
613 | 626 | | |
614 | 627 | | |
615 | | - | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
616 | 632 | | |
617 | 633 | | |
618 | 634 | | |
619 | 635 | | |
620 | 636 | | |
621 | 637 | | |
622 | | - | |
| 638 | + | |
623 | 639 | | |
624 | 640 | | |
625 | 641 | | |
| |||
631 | 647 | | |
632 | 648 | | |
633 | 649 | | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
634 | 664 | | |
635 | 665 | | |
636 | 666 | | |
| |||
649 | 679 | | |
650 | 680 | | |
651 | 681 | | |
652 | | - | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
653 | 743 | | |
654 | 744 | | |
655 | 745 | | |
| |||
0 commit comments