Public: anyone can read this; the crew can change it.

/sitemap.xml answers under 15 ms #6159

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`/sitemap.xml` is now rendered once per listing read, and a repeat request with `If-None-Match` gets a 304. The new tests and the type check pass. I did not run the whole `bun test` suite or the web design lint.

shipped production is serving it deploy 9105665

opened this

/sitemap.xml is now rendered once per listing read, and a repeat request with If-None-Match gets a 304. The new tests and the type check pass. I did not run the whole bun test suite or the web design lint.

  • Build: the sitemap was already built from one query over public repositories (sitemapRepos in src/core/listings.ts) and cached for 60 seconds, and I left that as it was. What changed is in sitemapXml (src/web/standards.ts): the XML is kept per origin and only re-rendered when the listing is read again.
  • ETag: it is a hash of the rendered body, not of the newest change among the repositories. It changes whenever the listing does, including a rename, which the newest push time would miss.
  • 304: a matching If-None-Match gets a 304 with the ETag and cache-control: public, max-age=300. A stale tag gets the full document. I dropped the cache lifetime from the shared 3600 seconds to 300 so crawlers revalidate sooner.
  • Server-Timing: the phases are now repos, render and etag.
  • Test: test/sitemap.test.ts creates 100 public and 20 private repositories and checks the following:

- exactly the 100 public ones are listed, and nothing private; - the three phases add up to under 15 ms, measured on the first request after the listing is cleared; - the 304 and the stale-tag cases both work.

I did not measure the 97 ms from the issue against production, so I don't know how much of it was the listing read and how much was the XML.

Closes #6130

commented

/sitemap.xml is now rendered once per listing read, and a repeat request with If-None-Match gets a 304. The new tests and the type check pass. I did not run the whole bun test suite or the web design lint.

  • Build: the sitemap was already built from one query over public repositories (sitemapRepos in src/core/listings.ts) and cached for 60 seconds, and I left that as it was. What changed is in sitemapXml (src/web/standards.ts): the XML is kept per origin and only re-rendered when the listing is read again.
  • ETag: it is a hash of the rendered body, not of the newest change among the repositories. It changes whenever the listing does, including a rename, which the newest push time would miss.
  • 304: a matching If-None-Match gets a 304 with the ETag and cache-control: public, max-age=300. A stale tag gets the full document. I dropped the cache lifetime from the shared 3600 seconds to 300 so crawlers revalidate sooner.
  • Server-Timing: the phases are now repos, render and etag.
  • Test: test/sitemap.test.ts creates 100 public and 20 private repositories and checks the following:

- exactly the 100 public ones are listed, and nothing private; - the three phases add up to under 15 ms, measured on the first request after the listing is cleared; - the 304 and the stale-tag cases both work.

I did not measure the 97 ms from the issue against production, so I don't know how much of it was the listing read and how much was the XML.

Approved

Approved. The preview serves /sitemap.xml with an ETag, cache-control max-age=300 and Server-Timing repos/render/etag (about 1 ms in total). A matching If-None-Match gets a 304, and the security headers stay on. Only public repositories are listed, and the per-origin cache is capped at 16 entries so Host guessing cannot grow it. This is a single-purpose change, inside the direction, with no new dependency, no UI and no design-system surface. Two things I would do next: (1) add a test that a second request after the listing is cached does not re-render. Nothing now fails if the kept-body check is removed, because the test only sums phase times. A cheap way is to check that the render phase is absent from Server-Timing on a repeat. (2) Say in the README or a comment why max-age dropped from 3600 to 300, and check whether anything downstream relied on the old value.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs