Skip to content

engine: fetch a font-face slot's candidate rules concurrently, not one at a time - #267

Merged
tannevaled merged 1 commit into
mainfrom
fix-fontface-slot-concurrency
Oct 10, 2026
Merged

tannevaled merged 1 commit into
mainfrom
fix-fontface-slot-concurrency

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Summary

  • LoadFontFaces groups @font-face rules into slots by (family, weight, italic) and, within a slot, tried each candidate in declaration order, stopping at the first that loaded.
  • This engine has no unicode-range model, so several genuinely distinct rules (a legacy icon-font shim splitting one family/weight by unicode-range, one rule per icon subset) collapse into a single slot and get treated as fallback alternatives of each other.
  • Confirmed live on www.cs.cmu.edu: its Font Awesome v4-compatibility shim declares five such rules, and the origin's own /webfonts/ path was returning HTTP 500 for all of them, each taking ~6.4s to fail. Trying them in series burned 50+ seconds of render time — found via the 500-page bench corpus (the first time it completed a full run, both earlier crash fixes holding).
  • Candidates in a slot now fire concurrently (deduped by a new srcsKey, so a rule parsed twice from two stylesheets still fetches once) and the lowest-declaration-order success wins once they all finish. The existing per-host concurrency cap (maxPerHostConcurrency, unchanged) still bounds real network concurrency, so this is a bounded speedup, not unlimited.

Test plan

  • go build ./...
  • go test ./... (all packages pass)
  • New test TestLoadFontFacesTriesSlotCandidatesConcurrentlyNotSequentially, stash-verified: ~460ms with the fix vs ~760ms on the unfixed code (local server, deterministic, 3 runs each)
  • fontfaces.go's LoadFontFaces/srcsKey both at 100% coverage; top-level engine package 96.1%→96.2% (no regression, confirmed via git stash)

🤖 Generated with Claude Code

…e at a time

LoadFontFaces groups @font-face rules into slots by (family, weight,
italic) and, within a slot, tried each candidate in declaration
order, stopping at the first that loaded. This engine has no
unicode-range model, so several genuinely distinct rules (a legacy
icon-font shim splitting one family/weight by unicode-range, one
rule per icon subset) collapse into a single slot and get treated
as fallback alternatives of each other.

Confirmed live on www.cs.cmu.edu: its Font Awesome v4-compatibility
shim declares five such rules, and the origin's own /webfonts/ path
was returning HTTP 500 for all of them, each taking ~6.4s to fail.
Trying them in series burned 50+ seconds of render time on a page
whose markup never asked for anything to be tried one at a time.

Candidates in a slot now fire concurrently (deduped by a new
srcsKey, so a rule parsed twice from two stylesheets still fetches
once) and the lowest-declaration-order success wins once they all
finish, instead of waiting out each failure in turn. The existing
per-host concurrency cap still bounds real network concurrency, so
this is a bounded speedup, not unlimited.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit d6c0fa1 into main Oct 10, 2026
7 checks passed
@tannevaled
tannevaled deleted the fix-fontface-slot-concurrency branch October 10, 2026 19:52
tannevaled added a commit that referenced this pull request Oct 10, 2026
… pages (#269)

Checked foundation.zurb.com (24.8s in the 500-page run, untouched by
this round's live testing) directly rather than assume the font-face
fix (round 168, PR #267) also explains it: still ~40s after that fix,
but DisableJS=true drops it to ~6.2s on the same page -- its slowness
is JS-settle-related, not the font-face-slot bug round 168 fixed.

cs.cmu.edu itself could not be cleanly re-measured: a careful single
re-check well after the fix merged still showed ~45s, consistent with
this round's own earlier live testing having triggered the origin's
own throttling (escalating response times observed before the fix
even shipped), which outlasted the session rather than the fix being
ineffective -- the deterministic local test (already in PR #267)
remains the real evidence for it.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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