Skip to content

feat: add memory accounting middleware to track and alert on request …#568

Open
oyinade247 wants to merge 1 commit into
CalloraOrg:mainfrom
oyinade247:task/memory-accounting
Open

feat: add memory accounting middleware to track and alert on request …#568
oyinade247 wants to merge 1 commit into
CalloraOrg:mainfrom
oyinade247:task/memory-accounting

Conversation

@oyinade247

Copy link
Copy Markdown

Closes #483

Description

Adds per-request heap delta tracking middleware for the GrantFox campaign. Samples process.memoryUsage().heapUsed at request start and end, logs a structured warning when the delta exceeds a configurable threshold.

Changes

New Files

  • src/middleware/memoryAccounting.ts — Factory function createMemoryAccountingMiddleware that returns an Express middleware. When enabled=false (default) it is a complete no-op — zero overhead, no heap sampling, no listener registration. When enabled, it captures heap at request start, hooks res.on('finish'), computes the delta, and emits a structured logger.warn via Pino if the delta exceeds thresholdMb.

  • src/middleware/memoryAccounting.test.ts — 11 unit tests covering disabled mode, threshold breaches, within-threshold behaviour, zero/negative deltas, request-id fallback, and zero-threshold edge case.

Modified Files

  • src/config/env.ts — Added two env vars:

    • MEMORY_ACCOUNTING_ENABLED (stringboolean, default false)
    • MEMORY_ACCOUNTING_THRESHOLD_MB (number, nonnegative, default 50)
  • src/config/index.ts — Exposes memoryAccounting.enabled and memoryAccounting.thresholdMb on the config object.

  • src/app.ts — Mounts the middleware after requestIdMiddleware and before metricsMiddleware.

Acceptance Criteria

Criterion Status
Delta sampled per request Sampled at start and finish event
Threshold respected Warning only when deltaBytes > thresholdBytes
Off mode is no-op When disabled, returns (_req, _res, next) => next() — no heap calls, no listeners
Logs structured Uses Pino logger with requestId, method, path, heapDeltaBytes, heapDeltaMb, thresholdMb

Security

  • No sensitive data logged (only method, path, numeric heap values)
  • Feature is opt-in via env var (defaults to off)
  • Input validation at env boundary via Zod schema (nonnegative, coerced number)

Testing

PASS src/middleware/memoryAccounting.test.ts
  createMemoryAccountingMiddleware
    when disabled
      ✓ calls next immediately without attaching finish listener
      ✓ does not sample heap when disabled
    when enabled
      ✓ calls next and registers finish listener
      ✓ logs warning when heap delta exceeds threshold
      ✓ does not log when heap delta is within threshold
      ✓ does not log when heap delta is zero
      ✓ does not log when heap delta is negative (GC reclaimed memory)
      ✓ uses fallback requestId when req.id is not set
      ✓ uses req.id as requestId when set
      ✓ warns with threshold of 0 on any positive delta
      ✓ samples heap at start and end of request

Tests: 11 passed

Usage

# Enable with 100 MB threshold
MEMORY_ACCOUNTING_ENABLED=true MEMORY_ACCOUNTING_THRESHOLD_MB=100 npm run dev

# Use default threshold (50 MB)
MEMORY_ACCOUNTING_ENABLED=true npm run dev

# Disabled (default) — zero overhead
npm run dev

@drips-wave

drips-wave Bot commented Jun 28, 2026

Copy link
Copy Markdown

@oyinade247 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

Add per-request memory accounting for slow-query investigations

1 participant