-
Notifications
You must be signed in to change notification settings - Fork 599
Fix session timeout due to timestamp frequency mismatch and activity tracking #1106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Update LastActivityTicks whenever a reference is acquired in the Started state, not just when reference count drops to 0. This ensures sessions with ongoing activity (POST requests) don't timeout even if a GET request is active. Co-authored-by: stephentoub <[email protected]>
Updated comment to be more precise about when LastActivityTicks is updated. Co-authored-by: stephentoub <[email protected]>
eiriktsarpalis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot the user comment from #1104 (comment) suggests that the root cause for the bug might be different. Could you check if that is the case?
Convert TimeSpan.Ticks to timestamp ticks using TimeProvider.TimestampFrequency. TimeSpan.Ticks uses 100-nanosecond intervals (10,000,000 per second), but TimeProvider.GetTimestamp() returns ticks based on TimeProvider.TimestampFrequency, which varies by platform (e.g., ~1,000,000,000 on macOS, ~10,000,000 on Windows). This was causing IdleTimeout to be incorrectly calculated, resulting in sessions timing out much faster than configured on platforms with different frequencies. Co-authored-by: eiriktsarpalis <[email protected]>
You're absolutely right! The user identified the actual root cause: a timestamp frequency mismatch between I've fixed this in commit 01982eb by converting timeSpan.Ticks * timeProvider.TimestampFrequency / TimeSpan.TicksPerSecondThis explains why the IdleTimeout had no effect - on macOS, a 10-hour timeout was being treated as ~360 seconds (~6 minutes). All tests pass with the fix. |
Moved the helper method to the end of the class per code review feedback. Co-authored-by: eiriktsarpalis <[email protected]>
Fix MCP Server Session Timing Out
Problem
Sessions were timing out prematurely due to two distinct bugs:
Timestamp frequency mismatch (primary bug):
IdleTimeout.Ticks(100-nanosecond intervals) was incorrectly used withTimeProvider.GetTimestamp()(platform-specific frequency). On macOS with ~1B ticks/second, a 10-hour timeout became ~6 minutes.Activity timestamp not updated:
LastActivityTicksonly updated when reference count dropped to 0, so POST requests during active GET connections didn't refresh the timeout.Plan
Root Causes
Bug 1: Timestamp Frequency Mismatch
In
StatefulSessionManager.csline 21,_idleTimeoutTickswas set toIdleTimeout.Ticks, which usesTimeSpan.Ticks(100-nanosecond units, always 10,000,000 per second). But line 115 used this withTimeProvider.GetTimestamp(), which returns ticks based onTimeProvider.TimestampFrequency(varies by platform: ~1,000,000,000 on macOS, ~10,000,000 on Windows).Bug 2: Activity Timestamp
In
StreamableHttpSession.cs,LastActivityTickswas updated inUnreferenceDisposable.DisposeAsync()only when_referenceCountreached 0. This meant POST requests during active GET connections didn't update the timestamp.Solutions
Bug 1 Fix: Added
GetIdleTimeoutInTimestampTicks()helper that convertsTimeSpan.Ticksto timestamp ticks:timeSpan.Ticks * timeProvider.TimestampFrequency / TimeSpan.TicksPerSecondBug 2 Fix: Updated
AcquireReferenceAsync()to setLastActivityTickswhenever a reference is acquired in the Started state.Testing
ActiveSession_WithPeriodicRequests_DoesNotTimeoutverifies ongoing activity prevents timeoutSecurity Summary
No vulnerabilities detected by CodeQL scanner.
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.