Skip to content

perf(registry): key the related-skills cache on the request slug - #277

Merged
harlan-zw merged 1 commit into
mainfrom
fix-skill-related-d1-load
Sep 22, 2026
Merged

harlan-zw merged 1 commit into
mainfrom
fix-skill-related-d1-load

Conversation

@harlan-zw

Copy link
Copy Markdown
Collaborator

🔗 Linked issue

Resolves #192

❓ Type of change

  • 🐞 Bug fix

📚 Description

Three fixes have gone at this already: the #158 retry, the #168 stale serve, and the response cache itself. Cold-key crawler sweeps still take D1 down, because none of them touched the part that runs on every request regardless.

findSkill sat in front of the cache. It is one D1 read, two when the slug needs the owner/repo/name fallback, and a cache hit paid it just the same. With 14,100 Skills in the registry, a crawler walking the catalog pays that read 14,100 times an hour no matter how warm the cache is. An unresolved slug was worse: two reads, a 404, and nothing cached, so the same dead URL cost the same thing forever.

Moving the lookup inside the cached function and keying on the slug drops a hit to zero D1 reads. Unresolved slugs get cached as a tagged missing on a 10 minute window, with no stale window so a newly indexed Skill is never served as absent.

What made me chase this rather than file it behind the other three: artifact delivery shares the database. During the 07:00 UTC burst on 22 Sep, Sentry logged 3,730 D1 DB is overloaded events with GET /api/skill-related/... as the top culprit by a factor of 40, and 100 resolutions failed SERVICE_UNAVAILABLE after burning the full 15 minute queue retry budget against an overloaded D1. One of them: created 07:10:40, failed 07:26:34. Lifetime that is 90 ready against 114 failed, so the catalog crawl is taking down the paid path.

The miss still costs five or six reads plus a Vectorize query. Precomputing the neighbour payload into a table would cut that to one indexed read, and that is the obvious follow-up, but it was pointless to do first while the per-request floor was still there.

Two things I am not sure about, and would rather a reviewer decided:

  • D1 overload 500s recur after the replayable-read retry fix #192 names server/utils/db.ts as the target. I did not touch it. The retry there looked correct to me; the load reaching it was the problem. Happy to be told the retry still needs work.
  • 10 minutes for the missing window is a guess. Short enough that a newly indexed Skill surfaces quickly, long enough to blunt a sweep. No data behind the number.

🤖 AI disclosure: Harlan Agent Kit modified this description. My AI open-source policy.

The slug lookup ran ahead of the cache, so every request cost one or two
D1 reads even on a hit. A crawler walking 14,100 Skill pages paid that
read 14,100 times an hour however warm the cache was.

On 2026-09-22 that floor saturated D1. Sentry recorded 3,730
`D1 DB is overloaded` events against this route, and artifact delivery,
which shares the database, failed 100 resolutions with
SERVICE_UNAVAILABLE after burning a full 15-minute retry budget.
Caching the response was tried twice before, on 2026-08-04 and in
SKILLD-1F, and could not help while the lookup sat outside it.

Move findSkill inside the cached function and key on the slug, so a hit
costs no D1 read. Cache the unresolved slug as a tagged `missing`
variant on a short window, because a crawler sweep over dead slugs used
to cost two reads each and cache nothing.

Bump the key to v4: a v3 value is an untagged raw response and must
never be read as a tagged entry.
@harlan-github-agent harlan-github-agent Bot added harlan-agent-running An Agent holds a Task on this issue or pull request right now. harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. labels Sep 22, 2026
@harlan-github-agent

harlan-github-agent Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

🤖 MERGED

Harlan Agent Kit posted this automated review. It is not Harlan's personal review or approval. AI open source policy. Last updated: 2026-09-22 10:49 UTC.

GitHub merged this pull request.

No material findings were recorded.

6d00f5ad-ac7e-4ed0-81a3-4662068cbe39

@harlan-github-agent harlan-github-agent Bot added harlan-agent-ready The automated Review passed every gate on this head commit. and removed harlan-agent-running An Agent holds a Task on this issue or pull request right now. harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. labels Sep 22, 2026
@harlan-zw
harlan-zw merged commit d60186e into main Sep 22, 2026
6 checks passed
@harlan-github-agent harlan-github-agent Bot removed the harlan-agent-ready The automated Review passed every gate on this head commit. label Sep 22, 2026
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.

D1 overload 500s recur after the replayable-read retry fix

1 participant