project-nomad/admin
Chris Sherwood e51ead616f fix(queue): singleton QueueService to stop ioredis connection leak
Every static call site instantiated a fresh QueueService (24 call sites
across 8 files). QueueService.getQueue() opens a BullMQ Queue per call
when not cached, and each Queue opens two ioredis connections (one for
commands, one blocking). Because every static call constructed a new
QueueService, its internal `queues` cache was never shared, every call
opened a fresh pair, and none were ever closed.

In normal operation this leaked a few connections per API hit. During
multi-batch ZIM ingestion after PR #872 (where EmbedFileJob.handle()
dispatches the next batch every 50 articles), every batch completion
opened two new connections. On NOMAD3 at ~one batch every 4s sustained,
that's ~1800 leaked connections/hour. Redis hit its 10,000-maxclient
ceiling in ~5 hours and the admin container fell into an EPIPE flood
that required a restart to recover.

Fix: collapse QueueService to a true process-wide singleton with a
private constructor and getInstance() accessor. The existing per-queue
Map is now shared across every dispatch / status / cleanup call, so each
queue's underlying connections are opened exactly once for the lifetime
of the process. close() now clears the map so the singleton can be torn
down cleanly if a graceful-shutdown hook is ever wired up.

Validated on NOMAD3 (RTX 5060, v1.32.0-rc.4 + this patch hot-applied):
under sustained multi-batch wikipedia_en_simple_all_nopic ingestion,
connected_clients held flat at 21-22 across a 5-minute window. Pre-fix
the same scenario climbed to 10,000+ over hours.
2026-05-13 13:48:21 -07:00
..
app fix(queue): singleton QueueService to stop ioredis connection leak 2026-05-13 13:48:21 -07:00
bin feat: curated content system overhaul 2026-02-11 15:44:46 -08:00
commands feat(Maps): regional map downloads via go-pmtiles extract (#780) 2026-05-03 13:47:53 -07:00
config fix: cache docker list requests, aiAssistantName fetching, and ensure inertia used properly 2026-04-03 14:26:50 -07:00
constants feat(Maps): regional map downloads via go-pmtiles extract (#780) 2026-05-03 13:47:53 -07:00
database feat(Content): custom ZIM library sources with pre-seeded mirrors (#593) 2026-05-04 11:30:59 -07:00
docs docs: update release notes 2026-05-04 19:30:06 +00:00
inertia fix(Maps): render notes in marker popup when populated 2026-05-05 10:38:56 -07:00
providers fix(System): self-heal stale updateAvailable flag after sidecar-driven update (#825) 2026-05-04 11:54:56 -07:00
public feat: switch all PNG images to WEBP (#575) 2026-04-03 14:26:50 -07:00
resources feat(Maps): regional map downloads via go-pmtiles extract (#780) 2026-05-03 13:47:53 -07:00
start feat(Content): custom ZIM library sources with pre-seeded mirrors (#593) 2026-05-04 11:30:59 -07:00
tests fix(UI): improve global map banner display logic (#702) 2026-04-28 20:55:25 -07:00
types fix(AI): vendor-aware AMD HSA override + benchmark discrete-GPU detection 2026-05-05 12:11:56 -07:00
util feat: display model download progress 2026-02-06 16:22:23 -08:00
views feat: initial commit 2025-06-29 15:51:08 -07:00
.editorconfig feat: initial commit 2025-06-29 15:51:08 -07:00
.env.example feat: Add Windows Docker Desktop support for local development 2026-01-19 10:29:24 -08:00
ace.js feat: initial commit 2025-06-29 15:51:08 -07:00
adonisrc.ts fix(System): self-heal stale updateAvailable flag after sidecar-driven update (#825) 2026-05-04 11:54:56 -07:00
eslint.config.js feat: openwebui+ollama and zim management 2025-07-09 09:08:21 -07:00
package-lock.json build(deps): bump picomatch in /admin 2026-05-04 10:50:13 -07:00
package.json chore(deps): pin all deps to exact versions 2026-05-04 17:45:18 +00:00
tailwind.config.ts feat: initial commit 2025-06-29 15:51:08 -07:00
tsconfig.json feat: initial commit 2025-06-29 15:51:08 -07:00
vite.config.ts fix(Maps): ensure proper parsing of hostnames (#640) 2026-04-03 14:26:50 -07:00