Server Overview: every visit reloads fontconfig and probes every offered script #1133
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1133
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What exists today
core/server_views.py:210-260OverviewView.get_context_datacalls_font_scripts()(core/server_views.py:161-176) on every visit, which callsdocuments/fonts.py:164-206renderable_scripts(). That calls_handles()(documents/fonts.py:239-259), which runsfontconfig.FcInitLoadConfigAndFonts()and builds a newPangoFT2FontMap: fontconfig reads its configuration and the cache of every installed font, and the image installsfonts-dejavu-core fonts-noto-core fonts-noto-cjk(docker/Dockerfile:273), several hundred faces. Then, for each of the 25PROBESand 1STYLE_PROBESentries the offered languages need,_script_drawablecreates a Pango context, loads a font and reads its cmap table.The answer depends only on the fonts installed on the machine and the offered languages, neither of which changes while a gunicorn worker runs in the image (the worker is recycled after about 500 requests,
docker/Dockerfile:380). The page is staff-only and visited occasionally, so the win is latency on that page, not throughput._theme_fonts()(core/server_views.py:179-196,documents/theme_assets.py:565-588) also reads every theme font file on each visit; that is plain file reading and cheaper, but has the same "cannot change while running" property.Measurement: not possible locally. Importing
weasyprint.text.ffion the development machine fails withcannot load library 'libgobject-2.0-0', so the cost ofFcInitLoadConfigAndFontswith the image's fonts could not be timed within the brief's limits.FontConfiguration()in WeasyPrint does the same load once per render, which is the order of cost involved.What would change
Memoise
renderable_scripts()for the life of the process, keyed on the offered scripts and styles (functools.lru_cacheon a helper takingfrozenset(languages.scripts_offered())andfrozenset(languages.styles_offered())), and the_handles()font map with it. Thecheck_fontsmanagement command (documents/management/commands/check_fonts.py:36) keeps asking afresh by calling the uncached function, so an operator who has just installed a font package and runs the command gets the live answer, and the page shows the fresh answer from the next worker restart onwards.script_drawsandfamily_draws(documents/fonts.py:209-236), used by tests to decide skips, would share the cached font map too, which speeds the test files that call them once per test.No library is needed.
What it saves or protects
small: one fontconfig load and 26 Pango font lookups per Overview visit become one per worker process; not measured (WeasyPrint's native libraries are absent on the development machine)
Accessibility
none
Decisions
_theme_fonts()too? Recommended: yes, keyed on the installed themes, in the same change.Found by the efficiency and reliability audit of 2026-10-30 (finding P1; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).