Skip to content

perf(registry): cut D1 reads and writes per Skill page render - #305

Merged
harlan-zw merged 2 commits into
mainfrom
perf/d1-skill-render
Sep 29, 2026
Merged

harlan-zw merged 2 commits into
mainfrom
perf/d1-skill-render

Conversation

@harlan-zw

@harlan-zw harlan-zw commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

❓ Type of change

  • 👌 Enhancement

📚 Description

On 2026-09-29 a residential-proxy crawler rendered 392 uncached Skill pages in two minutes, and D1 answered "overloaded". Each render cost about 15 D1 reads and, for any render older than 30 minutes, a GitHub refetch plus an UPDATE skills SET rendered_html…: 557 writes in that burst. Read replicas (#303) cannot absorb those writes, and 69% of D1 time went to one same-repo list query that sorted in a temp B-tree.

This PR makes three changes:

  • The detail resolves the Skill and its whole row in one statement. It reads the generated FAQ, tags, and summary in one statement.
  • An owner/repo/name slug skips the skills.slug lookup. That column is always owner/name (all 14,620 prod rows), so the lookup always missed.
  • A page view never writes a render back. Migration 0124 adds skills(owner, repo, modified_at DESC, name) and skills(owner, repo, source_resolved).

Measured on a local copy of production data (84k Skills), five sample Skills including the 1,344-Skill jeremylongshore/claude-code-plugins-plus-skills. Figures are per render, from workerd meta.rows_read:

D1 reads rows read writes
/api/skills/** before 10 859 1 (stale render)
/api/skills/** after 3 296 0
/api/skill-related/** before 5 1,724 0
/api/skill-related/** after 3 509 0

The same-repo list on the 1,344-Skill repo went from 4,034 rows to 8. The plan loses USE TEMP B-TREE FOR ORDER BY, with or without sqlite_stat1. The duplicate-candidates list is left out of these figures because the cache serves it.

Behaviour changes

  • An upstream SKILL.md edit now appears after the next repo sync. Before, it appeared about 30 minutes after someone viewed the page. The sync already re-renders when the tree SHA changes. In prod every live repo synced within 3 days, and 65% within 1 day. Subscribed repos get their own short window, so digests do not depend on page views. I found no copy that promises a faster refresh.
  • The 51 rows with no stored render still render live for the visitor, but the render is not persisted. reconcile-rendered repairs them every 6 hours.
  • rendered_at stops moving on page views, so the AI-ready Markdown updatedAt now tracks the last real render.

Not done here: the same-owner related list (about 1.4k rows on big owners) and the full repo name list for dependency links (1,345 rows on the biggest repo) are still the largest reads per render. idx_skills_owner_repo duplicates the primary key prefix, and I left it in place.

⚠️ #304 also adds a 0124_ migration. migration-naming rejects both a gap and a duplicate, so whichever PR merges second renumbers its file to 0125.

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

A crawler burst on 2026-09-29 rendered 392 uncached Skill pages in two
minutes and D1 answered "overloaded". Each render cost 15 reads and a
write-back of rendered_html whenever the stored render was over 30
minutes old.

The detail now resolves the Skill and its whole row in one statement and
reads generated content in one, the related route reuses the lookup row
for its commit source, and an owner/repo/name slug no longer tries the
slug column first. Page views stop writing renders; the repo sync and
reconcile-rendered own that. Migration 0125 indexes the same-repo list
and the resolved-Skill count.
The migration naming check rejects a gap, and 0124 is not on main yet. #304 also claims 0124, so whichever pull request merges second renumbers.
@harlan-zw
harlan-zw merged commit 20ed827 into main Sep 29, 2026
5 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