Skip to content

fix: close shared http.Agent on worker graceful shutdown (#225)#268

Merged
Xhristin3 merged 4 commits into
XStreamRollz:mainfrom
olaleyeolajide81-sketch:fix/issue-225-worker-http-agent-shutdown
Jun 16, 2026
Merged

fix: close shared http.Agent on worker graceful shutdown (#225)#268
Xhristin3 merged 4 commits into
XStreamRollz:mainfrom
olaleyeolajide81-sketch:fix/issue-225-worker-http-agent-shutdown

Conversation

@olaleyeolajide81-sketch

Copy link
Copy Markdown
Contributor

Problem

The shutdown hook in xstreamroll-processing/src/worker.ts was creating a brand-new Agent() and calling destroy() on it — a no-op for the actual axios HTTP keep-alive pool. HTTP connections were never properly closed on shutdown, leading to connection leaks.

Fix

  • Create a shared http.Agent({ keepAlive: true }) at module level (httpAgent)
  • Create an axios instance via axios.create({ httpAgent }) so all HTTP requests use the same pool
  • Call httpAgent.destroy() inside shutdown() to close all pooled sockets on graceful exit

Changes

  • xstreamroll-processing/src/worker.ts — shared agent, axios instance, destroy on shutdown; httpAgent and shutdown exported for testability
  • xstreamroll-processing/__tests__/worker.test.ts — new test suite (5 tests): Agent is a keep-alive http.Agent, axios.create receives the shared agent, destroy() is called on shutdown, process.exit(0) is called, shutdown is idempotent
  • xstreamroll-processing/package.json — added forceExit: true to jest config

Tests

All 18 tests pass (3 suites, exit code 0):

Test Suites: 3 passed, 3 total
Tests:       18 passed, 18 total

Closes #225

…z#225)

The shutdown hook was creating a brand-new Agent() and calling destroy()
on it — a no-op for the actual axios HTTP keep-alive pool.

Fix:
- Create a shared http.Agent({ keepAlive: true }) at module level
- Pass it to axios.create({ httpAgent }) so all requests reuse the pool
- Call httpAgent.destroy() in shutdown() to close all sockets on exit

Also:
- Export httpAgent and shutdown for testability
- Add __tests__/worker.test.ts covering: Agent type/keepAlive, axios
  wiring, destroy called on shutdown, process.exit(0), idempotency
- Add forceExit: true to jest config (background poll loop holds event loop)
- Rename GracefulShutdown instance to gracefulShutdown to avoid naming
  conflict with the exported shutdown function
- Replace new Agent().destroy() with httpAgent.destroy() in the
  'close http pool' hook — the previous code created a throwaway agent
  and destroyed it, which was a no-op for the actual connection pool
- Export shutdown as a testable async function wrapper around
  gracefulShutdown.requestShutdown()
- Remove duplicate 'import { Agent } from http' (http already imported)
@olaleyeolajide81-sketch

Copy link
Copy Markdown
Contributor Author

PR submitted for review and merging

@Xhristin3 Xhristin3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid fix @olaleyeolajide81-sketch! You nailed it — shared http.Agent({ keepAlive: true }) at module level, wired through axios.create({ httpAgent }), and destroyed on shutdown. Tests cover agent type, keepAlive flag, axios wiring, destroy-on-shutdown, process.exit(0), and idempotency. The naming conflict fix (gracefulShutdown vs shutdown export) was a nice catch too. Closes #225 perfectly. 🎯

@Xhristin3 Xhristin3 merged commit 4f63c77 into XStreamRollz:main Jun 16, 2026
1 check passed
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.

fix: Fix worker graceful shutdown to close actual axios pool

2 participants