fix(db): application_name op elke connectie + begrensde Prisma-pool #115
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/db-application-name"
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?
Waarom
Op 2026-08-16 liep de gedeelde Postgres drie keer vol. Nadat twee fixes in de web-app waren uitgerold (pool-per-module-scope, en één LISTEN-connectie per SSE-stream) bleef de teller op 86/100 staan, terwijl de web-app er nog maar 3 vasthield.
De meting die overbleef: 64 connecties vanaf het bridge-gateway-adres, met slechts 2 host-sockets naar de container. Ruim zestig kwamen dus ge-NAT binnen — remote MCP-clients over Tailscale. En omdat geen enkele connectie een
application_namedraagt, was de enige manier om dat vast te stellen NAT-forensiek: host-sockets tellen en aftrekken van wat de database ziet.Dat is geen werkbare diagnose-route voor een terugkerende storing.
Wat deze PR doet
1. Attributie. Nieuwe
src/db-connection.tslevert eenapplication_nameafgeleid vanS4M_SERVER,S4M_MODELen — indien aanwezig —SCRUM4ME_WORKER_INSTANCE_ID, bijvoorbeelds4m-mcp:mac:claudeofs4m-mcp:scrum4me-server:codex:idea-51. Ontbrekende identiteit wordt explicietunknown-host/unknown-modelin plaats van leeg, zodat een niet-gelabelde connectie te onderscheiden blijft van een verkeerd geconfigureerde. De naam wordt afgekapt op 63 bytes, want daar kapt Postgres zelf af.pg_stat_activitywordt hiermee direct bruikbaar:2. Begrenzing.
src/prisma.tsdeednew Pool({ connectionString: url })zondermax. node-postgres valt dan terug op 10 en negeert deconnection_limituit de URL, want dat is een Prisma-parameter en niet een van pg. Dezelfde fout-klasse is eerder in de web-app gerepareerd; dit is de MCP-helft ervan.Alle zeven dedicated
pg.Client-sites (wait-for-job×2,worker-heartbeat,update-job-status,presence/worker×2,queue/listen) plus de pool lopen nu via die module.application_namegaat als config-veld mee en niet gevouwen in de connection string: die herschrijven zou het wachtwoord kunnen her-encoderen.Wat deze PR bewust NIET doet
Bij het onderzoek was de vraag of de MCP dezelfde fout heeft als de SSE-routes, waar één gedeelde LISTEN-connectie 27 losse verbindingen verving. Het antwoord is nee, en multiplexen zou hier weinig opleveren.
De structuur lijkt op elkaar —
wait_for_job,queue_nextenqueue_wait_replyopenen elk een eigenpg.ClientmetLISTENvoor de duur van de wacht. Maar het verschil zit in de verdeling: bij de SSE-routes stonden er tientallen streams open binnen één proces, terwijl een MCP-proces in de praktijk één blokkerende wacht tegelijk heeft. Het aantal schaalt dus met het aantal client-processen, niet binnen een proces. Een in-process hub zou vrijwel niets samenvoegen.Lifecycle is ook in orde en blijft ongewijzigd: elke caller sluit zijn client in een
finally, wat ik per caller heb nagelopen. Er is geen lek — alleen lineaire groei met het aantal draaiende clients, en dát is een capaciteits- en configuratievraag, geen codefout.Verificatie
unknown-markering, whitespace-only identiteit, de 63-byte-grens,connection_limitgehonoreerd, fallbacks bij ontbrekende/niet-positieve/niet-hele/niet-URL-waarden, en beide config-vormen inclusief de eis dat de URL ongewijzigd doorgaat. 10/10 pass.tsc --noEmit: 211 fouten mét én zónder deze wijziging; met regelnummers genormaliseerd zijn de foutverzamelingen identiek.vitest run: 104 falende bestanden mét én zónder; het enige verschil is dat er één bestand bij komt dat slaagt (81 → 82). Geen enkele nieuwe failure.Die 211 type-fouten en 104 falende bestanden zijn pre-existing in een verse clone:
prisma:generateis niet gedraaid, dus de generated client ontbreekt. CI draait tegen een volledige checkout.Na de uitrol
Deze wijziging landt pas op de vloot na een image-rebuild met cache-bust (
update_mcp_workermetMCP_CACHE_BUST), en op de Mac pas nadat die zijn MCP herstart. Tot dan blijven bestaande connecties naamloos —application_namewordt bij het opzetten van de verbinding vastgelegd.Twee losse problemen, beide zichtbaar geworden bij de saturatie van de gedeelde Postgres op 2026-08-16. Attributie. De server stond op 100/100 met ~60 connecties vanaf remote hosts over Tailscale. Docker NAT die verbindingen, dus ze verschijnen allemaal als het bridge-gateway-adres en dragen geen application_name — de enige manier om ze toe te wijzen was NAT-forensiek (host-sockets tellen en aftrekken). Elke connectie die dit proces opent draagt nu een naam afgeleid van S4M_SERVER, S4M_MODEL en, indien aanwezig, SCRUM4ME_WORKER_INSTANCE_ID. Begrenzing. src/prisma.ts deed `new Pool({ connectionString })` zonder max. node-postgres valt dan terug op 10 en negeert de connection_limit uit de URL, want dat is een Prisma-parameter en niet een van pg. Dezelfde fout is eerder in de web-app gerepareerd; dit is de MCP-helft ervan. application_name gaat als config-veld mee en niet in de connection string: die herschrijven zou het wachtwoord kunnen her-encoderen. Alle zeven dedicated pg.Client-sites en de pool lopen nu via db-connection.ts. Het lifecycle-gedrag blijft ongewijzigd — de bounded-wait tools openen nog steeds een eigen LISTEN-client per wachtoproep en sluiten die in hun finally. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>