Skip to content

fix(session): bound JWTManager.Terminate cache deletion with a 5s timeout - #924

Merged
jasonmadigan merged 2 commits into
Kuadrant:mainfrom
SarthakB11:sarth/jwt-terminate-ctx
Jun 11, 2026
Merged

jasonmadigan merged 2 commits into
Kuadrant:mainfrom
SarthakB11:sarth/jwt-terminate-ctx

Conversation

@SarthakB11

@SarthakB11 SarthakB11 commented May 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Symmetric fix to #911 on the JWT-manager side of session teardown.

JWTManager.Terminate is invoked by the upstream MCP server library when the gateway needs to close a session. The SessionIdManager interface from mark3labs/mcp-go does not pass a context.Context, so the implementation creates one internally, but it used context.TODO(). That has no cancellation and no deadline, so if sessionDeleter is the Redis-backed cache and Redis is unreachable, the goroutine driving session expiry blocks indefinitely on the cache deletion call. That leaks the goroutine and can hold the upstream library's session-manager lock.

Replace context.TODO() with context.WithTimeout(context.Background(), terminateTimeout) and defer the cancel. terminateTimeout is a package-level constant set to 5 seconds so the value is visible at one site and easy to tune. Same shape as #911, just on the other end of the session lifecycle.

TestTerminate gains a subtest that wires JWTManager with a Deleter whose DeleteSessions blocks until the supplied context is canceled. Without the fix, Terminate blocks forever; with it, Terminate returns within the deadline plus a small buffer.

Verification

go build ./...
go vet ./...
go test -race -count=1 -timeout 60s ./internal/session/...
make lint

Summary by CodeRabbit

  • Bug Fixes

    • Session termination operations now have a bounded timeout to prevent indefinite blocking.
  • Tests

    • Added test coverage for session termination timeout behavior.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 10, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@SarthakB11 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 59 minutes and 58 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c3e1667b-0927-415a-a546-035144d9039b

📥 Commits

Reviewing files that changed from the base of the PR and between d26d9cc and c29a540.

📒 Files selected for processing (2)
  • internal/session/jwt.go
  • internal/session/jwt_test.go
📝 Walkthrough

Walkthrough

The PR bounds session deletion during termination by adding a terminateTimeout constant and wrapping sessionDeleter.DeleteSessions in a deadline-bound context instead of context.TODO(). Tests verify the timeout prevents indefinite blocking via a stalling deleter mock.

Changes

Session Termination Timeout Bounding

Layer / File(s) Summary
Timeout Configuration
internal/session/jwt.go
A terminateTimeout constant is defined to bound the session deletion operation.
Terminate Method Update
internal/session/jwt.go
JWTManager.Terminate now uses context.WithTimeout to create a deadline-bound context passed to sessionDeleter.DeleteSessions instead of context.TODO().
Timeout Verification Tests
internal/session/jwt_test.go
Test imports include context. A blockingDeleter test double simulates a stalled DeleteSessions call. TestTerminate subtest verifies that Terminate completes within the timeout budget rather than hanging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Kuadrant/mcp-gateway#911: Also modifies context passed to DeleteSessions to avoid using a request-scoped/canceled context.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: bounding JWTManager.Terminate cache deletion with a timeout. It is specific, clear, and directly reflects the core fix in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SarthakB11

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 10, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/session/jwt.go (1)

129-140: ⚡ Quick win

trim inline rationale comments to terse, timeless wording

Line 129-Line 130 and Line 138-Line 139 are more verbose than needed and include PR-specific history. Keep these comments short and implementation-focused.

As per coding guidelines, **/*.{go,ts,tsx,js,jsx,py}: Use minimal, DRY, terse comments in lowercase, only when necessary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/session/jwt.go` around lines 129 - 140, Trim the verbose inline
comments around terminateTimeout and the start of JWTManager.Terminate to
concise, implementation-focused notes: replace the multi-line historical
rationale on lines around terminateTimeout with a short comment like "// bounds
cache deletion in Terminate" and shorten the paragraph before
context.WithTimeout to "// derive background context with deadline for cache
deletion" (or similar), keeping references to terminateTimeout,
JWTManager.Terminate, m.sessionDeleter, and context.WithTimeout so the intent is
clear without PR-specific history.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/session/jwt_test.go`:
- Around line 227-242: Capture the error returned from
manager.Terminate("session-id") instead of discarding it (e.g., assign to err in
the goroutine and send it back to the test), then in the main test goroutine
assert that err matches the expected timeout/deadline behavior (for example
non-nil and context.DeadlineExceeded or contains "deadline exceeded") before or
alongside the existing elapsed-time checks; reference manager.Terminate,
terminateTimeout, deleter.called, and the done channel to locate and wire the
error assertion into the existing selects.

---

Nitpick comments:
In `@internal/session/jwt.go`:
- Around line 129-140: Trim the verbose inline comments around terminateTimeout
and the start of JWTManager.Terminate to concise, implementation-focused notes:
replace the multi-line historical rationale on lines around terminateTimeout
with a short comment like "// bounds cache deletion in Terminate" and shorten
the paragraph before context.WithTimeout to "// derive background context with
deadline for cache deletion" (or similar), keeping references to
terminateTimeout, JWTManager.Terminate, m.sessionDeleter, and
context.WithTimeout so the intent is clear without PR-specific history.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fdb86b23-34ad-406e-bb91-96337d366ca2

📥 Commits

Reviewing files that changed from the base of the PR and between baac9b0 and d26d9cc.

📒 Files selected for processing (2)
  • internal/session/jwt.go
  • internal/session/jwt_test.go

Comment thread internal/session/jwt_test.go Resolved
SarthakB11 added a commit to SarthakB11/mcp-gateway that referenced this pull request May 10, 2026
assert errors.Is(err, context.DeadlineExceeded) in the timeout test so
the test does not pass on a wrong-error or nil return. trim the inline
comments around terminateTimeout and the WithTimeout call to terse,
implementation-focused notes per the repo coding guideline (Minimal,
DRY, terse comments in lowercase, only when necessary).

Signed-off-by: SarthakB11 <[email protected]>
@david-martin

Copy link
Copy Markdown
Member

Good fix. This will need a minor rebase (typo fix landed on main in the same file). After rebasing, this should be good to go.

…eout

JWTManager.Terminate is called by the upstream MCP server library when
the gateway needs to close a session. The SessionIdManager interface
does not pass a context, so the implementation creates one internally,
but it used context.TODO() which has no cancellation and no deadline.
If sessionDeleter is the Redis-backed cache, a network outage means the
goroutine driving session expiry blocks indefinitely on Del, leaking
the goroutine and potentially holding the upstream library session
manager lock.

Replace context.TODO() with context.WithTimeout(context.Background(),
5 * time.Second). Mirrors the sessionCloser fix in Kuadrant#911 (Aman-Cool,
merged 2026-05-08): same class of bug, same fix shape, symmetric site.

Add TestJWTManager_Terminate_Timeout that wires JWTManager with a
Deleter mock whose DeleteSessions blocks until ctx is canceled, and
asserts Terminate returns within ~6s with a wrapped context.DeadlineExceeded.

Signed-off-by: SarthakB11 <[email protected]>
assert errors.Is(err, context.DeadlineExceeded) in the timeout test so
the test does not pass on a wrong-error or nil return. trim the inline
comments around terminateTimeout and the WithTimeout call to terse,
implementation-focused notes per the repo coding guideline (Minimal,
DRY, terse comments in lowercase, only when necessary).

Signed-off-by: SarthakB11 <[email protected]>
@SarthakB11
SarthakB11 force-pushed the sarth/jwt-terminate-ctx branch from d280115 to c29a540 Compare May 14, 2026 11:34
@SarthakB11

Copy link
Copy Markdown
Contributor Author

Rebased onto main. Picked up the errors import that landed alongside the typo fix; no behavior changes from my side. Build + race + lint clean locally.

@david-martin

Copy link
Copy Markdown
Member

Hey, thanks for the contribution. Just a heads up: reviews are currently being prioritised around the v0.7 milestone. PRs tied to v0.7 issues will be reviewed first. We'll get to this one, but it may take a bit longer than usual.

@jasonmadigan jasonmadigan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm. bounds the stalled-deleter path correctly, test proves the timeout fires.

@jasonmadigan
jasonmadigan enabled auto-merge (squash) June 11, 2026 15:41
@jasonmadigan
jasonmadigan merged commit 0707b2d into Kuadrant:main Jun 11, 2026
13 of 15 checks passed
malladinagarjuna2 pushed a commit to malladinagarjuna2/mcp-gateway that referenced this pull request Jun 16, 2026
…eout (Kuadrant#924)

* fix(session): bound JWTManager.Terminate cache deletion with a 5s timeout

JWTManager.Terminate is called by the upstream MCP server library when
the gateway needs to close a session. The SessionIdManager interface
does not pass a context, so the implementation creates one internally,
but it used context.TODO() which has no cancellation and no deadline.
If sessionDeleter is the Redis-backed cache, a network outage means the
goroutine driving session expiry blocks indefinitely on Del, leaking
the goroutine and potentially holding the upstream library session
manager lock.

Replace context.TODO() with context.WithTimeout(context.Background(),
5 * time.Second). Mirrors the sessionCloser fix in Kuadrant#911 (Aman-Cool,
merged 2026-05-08): same class of bug, same fix shape, symmetric site.

Add TestJWTManager_Terminate_Timeout that wires JWTManager with a
Deleter mock whose DeleteSessions blocks until ctx is canceled, and
asserts Terminate returns within ~6s with a wrapped context.DeadlineExceeded.

Signed-off-by: SarthakB11 <[email protected]>

* address coderabbit review on PR Kuadrant#924

assert errors.Is(err, context.DeadlineExceeded) in the timeout test so
the test does not pass on a wrong-error or nil return. trim the inline
comments around terminateTimeout and the WithTimeout call to terse,
implementation-focused notes per the repo coding guideline (Minimal,
DRY, terse comments in lowercase, only when necessary).

Signed-off-by: SarthakB11 <[email protected]>

---------

Signed-off-by: SarthakB11 <[email protected]>
Signed-off-by: malladi nagarjuna <[email protected]>
malladinagarjuna2 pushed a commit to malladinagarjuna2/mcp-gateway that referenced this pull request Jun 17, 2026
…eout (Kuadrant#924)

* fix(session): bound JWTManager.Terminate cache deletion with a 5s timeout

JWTManager.Terminate is called by the upstream MCP server library when
the gateway needs to close a session. The SessionIdManager interface
does not pass a context, so the implementation creates one internally,
but it used context.TODO() which has no cancellation and no deadline.
If sessionDeleter is the Redis-backed cache, a network outage means the
goroutine driving session expiry blocks indefinitely on Del, leaking
the goroutine and potentially holding the upstream library session
manager lock.

Replace context.TODO() with context.WithTimeout(context.Background(),
5 * time.Second). Mirrors the sessionCloser fix in Kuadrant#911 (Aman-Cool,
merged 2026-05-08): same class of bug, same fix shape, symmetric site.

Add TestJWTManager_Terminate_Timeout that wires JWTManager with a
Deleter mock whose DeleteSessions blocks until ctx is canceled, and
asserts Terminate returns within ~6s with a wrapped context.DeadlineExceeded.

Signed-off-by: SarthakB11 <[email protected]>

* address coderabbit review on PR Kuadrant#924

assert errors.Is(err, context.DeadlineExceeded) in the timeout test so
the test does not pass on a wrong-error or nil return. trim the inline
comments around terminateTimeout and the WithTimeout call to terse,
implementation-focused notes per the repo coding guideline (Minimal,
DRY, terse comments in lowercase, only when necessary).

Signed-off-by: SarthakB11 <[email protected]>

---------

Signed-off-by: SarthakB11 <[email protected]>
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.

3 participants