Track memory growth from in-process registries and add bounded eviction with metrics
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 22/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- nodejs, typescript
- Domain
- backend, observability, performance
Research direction
Start with src/monitoring/metrics-history.service.ts as the reference for the cap, trim and getRetention() pattern, then read src/rate-limiting/rate-limiter.service.ts around the memoryViolations cap and the in-memory bucket fallback. Next check the WebSocket removal paths in src/dashboard/websocket/connection-manager.service.ts and connection-pool.service.ts, and the retention in src/observability/profiling.service.ts. Done means each registry has a documented bound, emits size and eviction metrics, and passes an extended websocket.stress.spec.ts soak check; this needs maintainer agreement on the approach first.
Written by the indexing model from the issue text.
Description
Problem
Several services keep in-memory state whose growth is not obviously bounded:
src/rate-limiting/rate-limiter.service.ts:614-616—memoryViolationsis capped at 2000 entries, which is good, but the cap is a silent truncation with no metric.src/rate-limiting/rate-limiter.service.ts— in-memory rate-limit buckets when Redis is unavailable. These are keyed by client identifier, so the count scales with the number of distinct clients seen.src/dashboard/websocket/connection-manager.service.ts:148,194andconnection-pool.service.ts:284— Maps built per connection/session.src/observability/profiling.service.ts— tracks "hot functions" and, perPROFILING.md, retains CPU profiles and heap snapshots.
By contrast, src/monitoring/metrics-history.service.ts gets this right: it caps at MONITORING_HISTORY_MAX_POINTS (default 5760, lines 55-56), trims with slice (lines 108-109), and exposes getRetention() (line 134).
Why it matters
An unbounded Map in a long-lived Node process is a slow leak. It survives until the process restarts, degrades GC performance as it grows, and — for the WebSocket registries — retains connection objects and their associated buffers, which is the classic way a WebSocket server accumulates memory under churn.
The rate-limiter buckets are the most concerning because they are keyed by client identity, so a distributed scan or a large client population grows them without bound.
Suggested Direction
- Adopt the metrics-history pattern as the house standard: a configurable max size, explicit trimming, and an accessor exposing the retention parameters.
src/monitoring/metrics-history.service.tsis the reference implementation to copy. - Bound each registry:
- Rate-limit buckets: TTL-based expiry plus a max key count. Evict least-recently-used or oldest when over the cap.
- WebSocket registries: confirm connections are removed on disconnect. A
ConnectionManagerthat only ever adds is a leak; check every removal path, including abnormal closes. - Profiling data: bound retained profiles and snapshots, and drop old heap snapshots aggressively — they are large.
- Emit metrics for size and eviction counts. A silent cap (as with
memoryViolations) means you cannot distinguish a working eviction policy from data being quietly dropped. - Add a soak test.
websocket.stress.spec.tsalready exists; extend it to assert memory or registry size stabilises over many connect/disconnect cycles rather than growing linearly. - Consider moving large state to Redis where it must be shared across instances anyway (rate-limit buckets in particular).
Constraints
- Eviction must not weaken the rate limit — evicting an active client's bucket resets their allowance. Use TTL consistent with the window, not an arbitrary size cap, for security-relevant state.
- WebSocket disconnects must free resources even when the close is not graceful.
- Do not retain heap snapshots beyond a short period; they are memory-heavy by nature.
- Coordinate with the logging-facade issue before adding metrics, so the instrumentation is consistent.
Acceptance Criteria
- Every in-process registry has a documented bound (max size or TTL).
- Size and eviction counts are emitted as metrics.
- A soak test shows registry size stabilising rather than growing linearly.
- Rate-limit eviction does not reset an active client's window.
- WebSocket resources are freed on both graceful and abnormal disconnects.
-
getRetention()-style introspection exists for each bounded registry.
- Dominant language
- TypeScript
- Stars
- 7
- Forks
- 55
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 5
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from SourceXXL/alian_structure-api
-
good first issue help wanted security
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SourceXXL/alian_structure-api#266 ·
-
Parallelize the cache-warming loop in `cache-warming.service.ts` — warmers run strictly sequentiallyPossibly taken @syntaxsuuvam-spec claimed this 4 days ago. Opengood first issue performance
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SourceXXL/alian_structure-api#240 ·
-
documentation help wanted intermediate refactor
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
SourceXXL/alian_structure-api#215 ·
-
good first issue refactor tooling
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
SourceXXL/alian_structure-api#199 ·
-
help wanted intermediate refactor
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
SourceXXL/alian_structure-api#196 ·
All issues in SourceXXL/alian_structure-api
Similar issues
-
area:ui effort:S enhancement priority:P2
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
QuantumNous/new-api#7839 ·
Maintainers usually reply within 1 day
-
good first issue maintenance
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
dark-princezz/stellar-hooks#1010 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
interledger/rhyza#352 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day