Skip to content

chore(infra): derive DAO API database memory settings from cgroup limit - #2099

Open
pikonha wants to merge 2 commits into
devfrom
chore/dao-api-db-image
Open

chore(infra): derive DAO API database memory settings from cgroup limit#2099
pikonha wants to merge 2 commits into
devfrom
chore/dao-api-db-image

Conversation

@pikonha

@pikonha pikonha commented Aug 1, 2026

Copy link
Copy Markdown
Member

Why

All DAO databases run the stock postgres-ssl image with zero tuning, and every one sampled carries a hand-applied max_connections = 500 in postgresql.auto.conf — undocumented, invisible outside the volume, applied across four different memory tiers.

service memory.max auto.conf
uniswap-db 8 GB max_connections = 500
aave-db 6 GB max_connections = 500
ens-db 4 GB max_connections = 500
compound-db 4 GB max_connections = 500
shutter-db 2 GB max_connections = 500
nouns-db 2 GB max_connections = 500

500 backends is ~2.5 GB of unreclaimable memory. On the 2 GB tier that is an OOM the container cannot survive. PostgreSQLHighConnections cannot catch it either — it fires at 80% sustained for: 10m, which the OOM beats.

What

Wrap the stock image. The entrypoint reads /sys/fs/cgroup/memory.max and appends derived values as -c flags.

cap max_connections effective_cache_size
2 GB 75 1.3 GB
4 GB 80 2.6 GB
6 GB 120 3.9 GB
8 GB 160 5.2 GB

Derived rather than hardcoded because the fleet spans four tiers off one image, and a Railway plan change moves a service between tiers without touching the repo.

-c flags outrank postgresql.auto.conf, so this neutralises the existing 500 without writing to any volume, and reverts by pointing a service back at the stock image.

shared_buffers deliberately stays at its 128 MB default — raising it converts reclaimable page cache into unreclaimable shmem, spending safety margin on the two tiers with the least of it. Separate change.

⚠️ Each DB service must set PG_MAJOR

Production runs 17 Postgres services across three majors: 16 (×8), 17 (×4), 18 (×5). The base image version comes from a PG_MAJOR build arg, which Railway populates from the service's variables.

There is no default on purpose. An unset PG_MAJOR fails the build, leaving the running container serving. A wrong default would build cleanly and then crashloop on database files are incompatible with server.

major services
16 uniswap, ens, compound, nouns, shutter, gitcoin, obol, telegram-bot, scroll
17 aave, address-enrichment, erpc, db-scroll
18 authful, fluid, lil-nouns, tornado, user

Verified locally

  • --self-test passes 8 cases: 4 fleet tiers, both clamp boundaries, 2 fallback paths
  • Builds and boots on all three majors with Railway's PGDATA; each reports max_connections=75, effective_cache_size=1331MB, ssl=on at a 2 GB limit
  • Unset PG_MAJOR fails the build, as designed
  • Derives correctly at 2 GiB (75) and 6 GiB (120)
  • ssl = on — the entrypoint wrap does not break the base image's cert setup
  • With max_connections = 500 written into a real auto.conf and restarted: SHOW max_connections75, sourcecommand line
bash infra/dao-api-db/entrypoint.dao-api-db.sh --self-test

Not in this PR

  • shared_buffers at 128 MB fleet-wide
  • Collation version mismatch (2.36 → 2.41) on uniswap-db — possible silent text-index corruption, needs REINDEX DATABASE before REFRESH COLLATION VERSION
  • postgres-exporter's DATA_SOURCE_NAME holds plaintext superuser credentials for 14 production databases in one variable

🤖 Generated with Claude Code

All 14 DAO databases run the stock postgres-ssl image with no tuning, and
every one of them carries a hand-applied `max_connections = 500` in
postgresql.auto.conf — undocumented, invisible outside the volume, and
applied across four different memory tiers (2/4/6/8 GB).

500 backends is roughly 2.5 GB of unreclaimable memory. On the 2 GB tier
(nouns-db, shutter-db) that is an OOM the container cannot survive, and
PostgreSQLHighConnections cannot catch it: it fires at 80% sustained for
10m, which the OOM beats.

Wrap the stock image so the entrypoint reads /sys/fs/cgroup/memory.max and
appends the derived values as -c flags. Command-line options outrank
postgresql.auto.conf, so this neutralises the existing 500 without writing
to any volume, and reverts by pointing a service back at the stock image.

  2 GB -> max_connections=75   effective_cache_size=1.3 GB
  4 GB -> max_connections=80   effective_cache_size=2.6 GB
  6 GB -> max_connections=120  effective_cache_size=3.9 GB
  8 GB -> max_connections=160  effective_cache_size=5.2 GB

shared_buffers is deliberately left at its 128 MB default: raising it
converts reclaimable page cache into unreclaimable shmem, which would spend
safety margin on the two tiers that have the least of it. Separate change.

Verify with: bash infra/dao-api-db/entrypoint.dao-api-db.sh --self-test

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
anticapture-storybook Ready Ready Preview Aug 1, 2026 4:14pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
anticapture Ignored Ignored Aug 1, 2026 4:14pm

Request Review

@railway-app

railway-app Bot commented Aug 1, 2026

Copy link
Copy Markdown

🚅 Deployed to the anticapture-pr-2099 environment in anticapture-infra

Service Status Web Updated (UTC)
uniswap-indexer-offchain ✅ Success (View Logs) Aug 2, 2026 at 4:37 pm
ens-indexer-offchain ✅ Success (View Logs) Aug 2, 2026 at 4:37 pm
gitcoin-indexer-offchain ✅ Success (View Logs) Aug 2, 2026 at 4:37 pm
compound-indexer-offchain ✅ Success (View Logs) Aug 2, 2026 at 4:36 pm
shutter-indexer-offchain ✅ Success (View Logs) Aug 2, 2026 at 8:10 am
prometheus ✅ Success (View Logs) Aug 1, 2026 at 5:08 pm
grafana ✅ Success (View Logs) Web Aug 1, 2026 at 5:08 pm
authful ✅ Success (View Logs) Web Aug 1, 2026 at 4:13 pm
gateful ✅ Success (View Logs) Web Aug 1, 2026 at 4:12 pm
loki ✅ Success (View Logs) Aug 1, 2026 at 4:12 pm
otelcol ✅ Success (View Logs) Aug 1, 2026 at 4:12 pm
alertmanager ✅ Success (View Logs) Web Aug 1, 2026 at 4:12 pm
tempo ✅ Success (View Logs) Aug 1, 2026 at 4:12 pm
mcp ✅ Success (View Logs) Web Aug 1, 2026 at 4:11 pm
docs ✅ Success (View Logs) Web Aug 1, 2026 at 4:11 pm
aave-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
scroll-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
gitcoin-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
obol-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
obol-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
gitcoin-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
ens-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
shutter-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
ens-relayer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
tornado-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
fluid-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
uniswap-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
compound-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
lil-nouns-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
tornado-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
shutter-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
lil-nouns-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
ens-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
aave-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
compound-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
uniswap-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
nouns-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
address-enrichment ✅ Success (View Logs) Web Aug 1, 2026 at 4:10 pm
fluid-indexer ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
nouns-api ✅ Success (View Logs) Aug 1, 2026 at 4:10 pm
erpc ✅ Success (View Logs) Web Aug 1, 2026 at 4:10 pm
nodeful ✅ Success (View Logs) Aug 1, 2026 at 4:09 pm
user-api ✅ Success (View Logs) Web Aug 1, 2026 at 4:07 pm
scroll-api ✅ Success (View Logs) Aug 1, 2026 at 4:07 pm

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 074b1e2c74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# The base image's ENTRYPOINT (wrapper.sh) sets up SSL certs and pgbackrest, so
# we don't replace it — entrypoint.dao-api-db.sh derives a couple of settings from
# the container's memory limit and then execs wrapper.sh with them appended.
COPY entrypoint.dao-api-db.sh /entrypoint.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Copy the entrypoint from its repository-relative path

With the repository-root build context selected by dao-api-db.railway.toml, this source resolves to /entrypoint.dao-api-db.sh, but a repo-wide search shows the file exists only under infra/dao-api-db/; the image build therefore fails before deployment. Docker's COPY documentation specifies that local sources are resolved relative to the root of the build context, so this must copy infra/dao-api-db/entrypoint.dao-api-db.sh (or explicitly change the build context).

Useful? React with 👍 / 👎.

The fleet is not on one major: production runs 17 Postgres services across
16 (x8), 17 (x4) and 18 (x5). A hardcoded :16 base would start against a
newer PGDATA and exit with "database files are incompatible with server",
crashlooping 9 of 17 databases.

Take the major from a PG_MAJOR build arg, which Railway populates from the
service's variables. No default on purpose: an unset PG_MAJOR fails the
build and leaves the running container serving, whereas a wrong default
would build cleanly and then crashloop.

Booted and verified on all three majors at a 2 GB limit — each reports
max_connections=75, effective_cache_size=1331MB, ssl=on.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

🔍 Vercel preview: https://anticapture-c9dodln4b-ful.vercel.app

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