Repository navigation
Size the Linux compose store's workers and work_mem from the product's own formula (#4322) - #4400
Merged
Merged
Conversation
…s own formula (#4322) timescaledb-tune, which the official image runs on every start, sizes worker counts from CPU count and work_mem from the container's memory limit -- neither matches this product's needs. Measured under docker run --memory at 2/4/8 GB: tune gives 16/34 background/worker-process slots (PostgreSQL's own default shape, which starves TimescaleDB's per-hypertable compression/retention/CAGG policy jobs) and ~4 MB work_mem (below the managed store's own 16 MB floor at these sizes, and the #4310 spill evidence shows the cost of staying there). Path B (claude-desktop 2026-09-26 07:17Z): the service doesn't manage this container, so explicit flags land ONLY where tune's own choice is a known miss, each with its floor/cap documented in a comment. Everything else (shared_buffers, effective_cache_size, maintenance_work_mem, max_connections) stays on tune's own container-derived sizing. - store.command now sets timescaledb.max_background_workers=74 and max_worker_processes=85, the same formula BuildWorkerSizingConfAppend writes for the managed Windows store (HypertableCount + 2 / 3 + that + 8), and work_mem=16MB, the managed store's own RAM/512 floor for any host at or under 8 GB. - a commented mem_limit example, never a default. - CiComposeWorkerSizingTests pins the compose file's flags against the live HypertableCount formula and against the shared_preload_libraries line, the same shape as CiClusterWorkerSizingTests for CI's throwaway cluster. RED confirmed on dev's pre-fix compose file: 3 of 4 pins fail (worker sizing absent, work_mem absent); the fourth (preload libraries) already passed since that line predates this change.
erikdarlingdata
marked this pull request as ready for review
September 26, 2026 10:58
This was referenced Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #4322.
Why
On Linux the service never manages the store container, and it doesn't read the container's own memory limit.
timescaledb-tune,which the official
timescale/timescaledbimage runs on every start, already sizes the container from itscgroup limit the way the managed Windows store sizes from host RAM. So the compose file should carry
explicit flags ONLY where tune's own choice is a known miss.
Measured (#4322 comment 5841262514) under
docker run --memoryagainsttimescale/timescaledb:latest-pg17:I re-measured worker sizing myself with the same command (2 GB / 8 GB,
SHOW timescaledb.max_background_workers, max_worker_processes, max_connections): tune gives 16 / 34 background workers / worker processes atboth sizes — PostgreSQL's own default shape.
.github/workflows/build.yml(~936-952) says why that's wrongfor this product: TimescaleDB's per-hypertable compression/retention/CAGG policy jobs are launched by
background workers, and at 8-16 slots most policy runs never happen.
The spill evidence (#4310, ~4 MB work_mem):
QueryStoreTopSqlat 7 days spilled ~38 MB perworker across 5 workers. Tune's own work_mem (~4 MB, measured above) is below the managed store's own
floor —
DeriveMemorySettings'clamp(RAM/512, 16 MB, 64 MB)already floors to 16 MB for any host ator under 8 GB (8 GB / 512 = 16 MB exactly) — at every size this container is measured at, so a single fixed
literal is the right answer; no
TS_TUNE_MAX_CONNScompanion needed (fewer hard-coded numbers thanderiving a second one to make tune's own number come out right). cc #4310.
What changes
Darling/compose/docker-compose.yml'sstore.command:gains three-cflags, each commented with itsfloor/cap and reasoning inline:
timescaledb.max_background_workers=74max_worker_processes=85work_mem=16MB74/85 is the SAME formula the managed Windows store writes (
DarlingManagedPostgres.BuildWorkerSizingConfAppend):max_background_workers = HypertableCount + 2,max_worker_processes = 3 + max_background_workers + 8.TimescaleSupport.HypertableCountis 72 today → 74 and 85.Also added: a commented
mem_limit: 8gEXAMPLE only (never a default — hosts vary, a limit could starve abig host's store), and a block comment above
command:explaining the boundary (what tune keeps,what's overridden, and why).
shared_preload_libraries=timescaledb,pg_stat_statementsis untouched — still the first-cflag, stillwins by command-line precedence.
Reading the container's cgroup limit from inside the service is not part of this change: the service doesn't manage this container, and tune already reads the same limit directly.
Values vs the Windows derivation
shared_bufferseffective_cache_sizemaintenance_work_memwork_memmax_connectionstimescaledb.max_background_workers/max_worker_processesHypertableCount+2/3+that+8Test plan
New
CiComposeWorkerSizingTests(run in-process on macOS against the realDarling.Tests.dll):RED confirmed against pre-fix
origin/dev(6e501af), same test file dropped into a detached worktree:(The fourth pin,
shared_preload_libraries, correctly passed on dev too — that line predates this change.)Live check, new compose flags,
docker run --memory(same image, same command line):2 GB safety arithmetic (all-connections-busy worst case, same bound
DeriveMemorySettingsdocuments —~3 concurrent sort/hash nodes per connection): 25 × 3 × 16 MB = 1200 MB, plus
shared_buffers' 512 MB =1712 MB, under the 2 GB limit with headroom for the rest of the server.
Build:
Darling.Tests.csprojandLite.Tests.csprojboth 0 Warning(s) / 0 Error(s) with-p:EnableWindowsTargeting=true.Lite.Testscarries no compose-related change and is unaffected.Notes
work_memchoice — the spill evidence that motivated the 16 MB floor came from thatissue's rig.
timescaledb-tunealready reads the same cgroup limit directly.CHANGELOG entry
SECTION: Changed
ENTRY:
work_memfrom the product's ownformula, instead of leaving them at
timescaledb-tune's CPU/memory-derived defaults ([Size the Linux compose store's workers and work_mem from the product's own formula (#4322) #4400]) - thecompose deployment's store container was running PostgreSQL's default worker ceiling (most TimescaleDB
policy jobs never launched) and a
work_memlow enough to spill sorts that a modest analytical queryneeds. The background-worker slots now use the managed store's formula, and
work_memis pinned to the managed store's 16 MB floor.REF:
[#4400]: #4400