Context
src/app.ts:201-211 installs a setInterval(purge..., 60_000) on every Fastify instance. In split-port mode, both api and admin instances share the same services object and both timers fire.
Problem / Observation
Every minute, the purge functions (purgeExpired on sessions/challenges/admin equivalents, purgeOld on login_attempts) run twice on the same DB rows. The DELETEs are idempotent so correctness is fine, but it doubles the IO and is exactly what the inline comment at lines 197-200 was trying to acknowledge ("the inserts are idempotent" — wrong file pattern, but the spirit is there).
Proposed approach
Move the purge timer to buildServices so it's tied to the shared services lifecycle, not to each Fastify instance. Add a services.startBackgroundTasks() / stopBackgroundTasks() pair called once from index.ts. Clean it up on the last app close.
Acceptance criteria
Context
src/app.ts:201-211 installs a
setInterval(purge..., 60_000)on every Fastify instance. In split-port mode, both api and admin instances share the sameservicesobject and both timers fire.Problem / Observation
Every minute, the purge functions (
purgeExpiredon sessions/challenges/admin equivalents,purgeOldon login_attempts) run twice on the same DB rows. The DELETEs are idempotent so correctness is fine, but it doubles the IO and is exactly what the inline comment at lines 197-200 was trying to acknowledge ("the inserts are idempotent" — wrong file pattern, but the spirit is there).Proposed approach
Move the purge timer to
buildServicesso it's tied to the shared services lifecycle, not to each Fastify instance. Add aservices.startBackgroundTasks()/stopBackgroundTasks()pair called once fromindex.ts. Clean it up on the last app close.Acceptance criteria