Skip to content

fix: guard ctx.create() against ended context after client disconnect#109

Merged
melikhov-dev merged 2 commits intomainfrom
fix/guard-ctx-create-after-disconnect
Mar 2, 2026
Merged

fix: guard ctx.create() against ended context after client disconnect#109
melikhov-dev merged 2 commits intomainfrom
fix/guard-ctx-create-after-disconnect

Conversation

@melikhov-dev
Copy link
Contributor

@melikhov-dev melikhov-dev commented Mar 2, 2026

Closes #108

Summary

  • Add isEnded() guards in wrapMiddleware and wrapRouteHandler (src/router.ts) to prevent ctx.create() from throwing when middleware or route handler runs after client disconnects and the parent context is already ended
  • In wrapMiddleware: skip child context creation and call next() early
  • In wrapRouteHandler: skip handler execution entirely

Test plan

  • Added 2 tests in context-lifecycle.test.ts that simulate real client disconnect via socket.destroy()
  • Without the fix, tests crash the process with Error: Trying to create child context from already ended context (unhandled rejection)
  • With the fix, all new tests pass

Add isEnded() checks in wrapMiddleware and wrapRouteHandler to prevent
crashes when middleware or route handlers run after the client disconnects
and the original context is already ended.
@melikhov-dev melikhov-dev force-pushed the fix/guard-ctx-create-after-disconnect branch 2 times, most recently from dd837ca to 299dedb Compare March 2, 2026 22:04
const nodekit = new NodeKit();
const app = new ExpressKit(nodekit, {
'GET /test': {
beforeAuth: [slowMiddleware],
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion(blocking): Two tests look almost the same. Looks like you should add another middleware here to test this case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

"@commitlint/config-conventional": "^17.7.0",
"@gravity-ui/eslint-config": "^3.2.0",
"@gravity-ui/nodekit": "^2.7.0",
"@gravity-ui/nodekit": "^2.10.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

issue(blocking): You should up nodekit in peer dependencies because you use isEnded function

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it would be better to add some fallback to not make a major release because of upgrading peer deps

Copy link
Contributor Author

@melikhov-dev melikhov-dev Mar 2, 2026

Choose a reason for hiding this comment

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

issue(blocking): You should up nodekit in peer dependencies because you use isEnded function

Switched to reqCtx.abortSignal.aborted for backward compatibility.

Copy link
Contributor

Choose a reason for hiding this comment

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

issue(blocking): You should up nodekit in peer dependencies because you use isEnded function

Switched to reqCtx.abortSignal.aborted for backward compatibility.

But abortSignal was added in the 2.5.0 version of nodekit, and we support ^1.6.0 || ^2.0.0 in expresskit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But abortSignal was added in the 2.5.0 version of nodekit, and we support ^1.6.0 || ^2.0.0 in expresskit.

Good catch! Added optional chaining (abortSignal?.aborted) so it won't break on nodekit < 2.5.0. The guard simply won't activate, preserving the old behavior.

@melikhov-dev melikhov-dev force-pushed the fix/guard-ctx-create-after-disconnect branch from 299dedb to cfdb360 Compare March 2, 2026 22:12
@melikhov-dev melikhov-dev requested a review from DakEnviy March 2, 2026 22:14
Required for isEnded() method on AppContext type.
@melikhov-dev melikhov-dev force-pushed the fix/guard-ctx-create-after-disconnect branch from cfdb360 to ac08d52 Compare March 2, 2026 22:23
@melikhov-dev melikhov-dev merged commit c736744 into main Mar 2, 2026
5 checks passed
@melikhov-dev melikhov-dev deleted the fix/guard-ctx-create-after-disconnect branch March 2, 2026 22:34
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.

ctx.create() throws in middleware chain after client disconnect (nodekit 2.10.0 compatibility)

2 participants