Skip to content

perf(share): cuts share card generation cost - #3148

Open
seferturan wants to merge 3 commits into
mainfrom
perf/share-fonts-from-r2
Open

perf(share): cuts share card generation cost#3148
seferturan wants to merge 3 commits into
mainfrom
perf/share-fonts-from-r2

Conversation

@seferturan

@seferturan seferturan commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

🎶 Notes 🎶

  • Cold share card generation was dominated by two things, measured per stage
    • satori render was 60-72% of the request
    • the fonts were fetched from cdn-sveltekit-og.ethercorps.io on every cold generation, 6s to 19s in Sentry over the past week, which is long enough for a scraper to give up before the card renders
  • Loads the fonts from R2 instead
    • reads assets/fonts/NotoSans-Regular.ttf and assets/fonts/NotoSans-Bold.ttf from the walter bucket the endpoint already binds, memoised per isolate
    • falls back to the sveltekit-og defaults when the bucket or an object is missing, so dev keeps working and a bad upload degrades instead of breaking
    • caches successes only, so a failed read retries instead of poisoning the isolate
    • fonts are already uploaded and verified reachable
  • Collapses the poster shadow to a single layer
    • satori render, averaged over 3 samples per variant: open-graph 783ms to 538ms, feed 1413ms to 764ms. 31% and 46% off
    • cost tracks the area the blur covers rather than the number of layers, so alpha is free
    • ⚠️ keep the alpha low. A single layer at 0.5 concentrates the whole shadow into a visible slab with a hard edge along the poster radius, where five faint layers blended into a smooth falloff. 0.22 over a 32px blur reads like the original
  • Resolves the poster and the fonts in parallel
    • neither depends on the other, and neither can reject, so Promise.all does not change the failure behaviour

🚀 Deploying 🚀

  • No cache purge needed this time
    • cards already in R2 keep the old shadow, new ones get the new one
    • minor cosmetic drift only, sorts itself out once we prune automatically

🤔 Later 🤔

  • Automatic pruning of cached cards, tackled separately
  • In-flight dedupe. When several scrapers hit the same new url at once they each render it from scratch. Worth doing now that render is the bulk of the cost

@trakt-bot
trakt-bot Bot enabled auto-merge (rebase) August 18, 2026 10:27
@seferturan
seferturan requested a review from rectifyer August 18, 2026 10:28
@deepsource-io

deepsource-io Bot commented Aug 18, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 4056525...68d9723 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Coverage  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Aug 18, 2026 11:16a.m. Review ↗
Code coverage Aug 18, 2026 11:16a.m. Review ↗

Code Coverage Summary

Language Line Coverage (Overall)
Aggregate
69%
[▲ up 0.1% from main]
Javascript
69%
[▲ up 0.1% from main]

➟ Additional coverage metrics may have been reported. See full coverage report ↗


Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

sveltekit-og fetches NotoSans regular and bold from cdn-sveltekit-og.ethercorps.io
on every cold generation. Sentry has that pair at 6s to 19s across the past week,
which is long enough for a social scraper to give up before the card renders, and
it puts a third party in the critical path of every share image.

Reads both faces from the R2 bucket the endpoint already binds, memoised per
isolate. Falls back to the sveltekit-og defaults when the bucket or an object is
missing, so dev keeps working and a bad upload degrades instead of breaking.

Needs assets/fonts/NotoSans-Regular.ttf and assets/fonts/NotoSans-Bold.ttf
uploaded to walter before this has any effect.
Satori render time on the poster shadow, averaged over three samples per
variant: the five layer stack cost ~783ms on open-graph and ~1413ms on feed,
against ~538ms and ~764ms for one layer. That is 31% and 46% off the render.

Cost tracks the area the blur covers, not the number of layers, so alpha is
free. Keeping it low matters: a single layer at 0.5 alpha concentrates the whole
shadow into a visible slab with a hard edge along the poster radius, where five
faint layers blended into a smooth falloff. 0.22 over a 32px blur reads like the
original without the cost.
Both were awaited in sequence even though neither depends on the other, so the
request paid for both round trips back to back. Neither can reject, they both
degrade internally, so Promise.all does not change the failure behaviour.
@seferturan
seferturan force-pushed the perf/share-fonts-from-r2 branch from d6c9462 to 68d9723 Compare August 18, 2026 11:16
@seferturan
seferturan requested a review from rudf0rd August 18, 2026 16:05
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