Memory: reading month names or language names loads every language into each process #1086
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1086
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?
Found while measuring the test workers' memory for #1033. Two production paths load data for every language just to read a little of it, and each process keeps it for its whole life:
csv_import._month_namesloads all 85 merged translation catalogues (about 110 MB per process) to know the month names in every language when reading a date from a CSV.language_names._indexloads every CLDR locale from Babel (about 75 MB) to name each language in every other.On a small instance (Ragnar is a Raspberry Pi), that is close to 200 MB per gunicorn worker, held forever, for data most requests never touch.
What to do
Not a 0.5.0 blocker; the test side was fixed in #1033's item 3.
From the efficiency and reliability audit of 2026-10-30 (finding M2), what this issue does not yet say:
src/postulo/core/language_names.py:188-199_index()(lru_cache(maxsize=1)) loops over("en", *languages.NATIVE_NAMES)(86 locales) and, for each, all 637 offered codes, through_locale()(:97-106,lru_cache(maxsize=256)). Babel keeps each parsed locale inbabel.localedata._cachefor the life of the process.match()uses it; callers arecore/importer.py:1537(archive import),resume/candidate.py:1461(CV candidate, also reached from the Europass reader),resume/importing.py:211(CV import),resume/management/commands/match_languages.py:34, and migrationresume/migrations/0015_match_spoken_languages.py:18.Measured with
tracemallocunderpostulo.config.settings.test(audit/m_scripts/mem.py m2): 62.2 MB retained, 68.3 MB peak, 2.82 s, Babel cache 95 locales. For comparison,name("pt", "en")alone holds 3.7 MB with 2 locales, andlisting("en")adds 0.1 MB.#1086 already says this path loads every CLDR locale (about 75 MB) and asks for the offered languages plus an LRU bound. What #1086 does not say, worth a comment on it rather than a new issue:
match_languagescommand, migration 0015);jobs/places._translated_countries()(M1): after M1 has run,_index()adds only 7.2 MB, so bounding one without the other saves nothing;Nothing new to file. Add the three points above as a comment on #1086 and link it to the M1 issue.
Checked against
mainatdaee30b15(2026-10-30).