-
Notifications
You must be signed in to change notification settings - Fork 3.1k
feat: add idle timeout for StreamableHTTP sessions #1994
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
base: v1.x
Are you sure you want to change the base?
Conversation
|
Can't the task manage itself? I don't think we want the overhead of a background task that checks other tasks. This seems something the specification should mention. |
debfd7d to
73f4cf2
Compare
f8b58ad to
3b38262
Compare
Add a session_idle_timeout parameter to StreamableHTTPSessionManager that enables automatic cleanup of idle sessions, fixing the memory leak described in #1283. Uses a CancelScope with a deadline inside each session's run_server task. When the deadline passes, app.run() is cancelled and the session cleans up. Incoming requests push the deadline forward. No background tasks needed — each session manages its own lifecycle. - terminate() on the transport is now idempotent - Effective timeout accounts for retry_interval - Default is None (no timeout, fully backwards compatible) Github-Issue: #1283
3b38262 to
2c87708
Compare
- Remove unrelated blank line between logger.info and try block - Only create CancelScope when session_idle_timeout is set, keeping the no-timeout path identical to the original code - Add docstring to _effective_idle_timeout explaining the 3x retry_interval multiplier rationale
3bdc230 to
7345bd7
Compare
The helper silently clamped the user's configured timeout to retry_interval * 3, which is surprising. Users should set a timeout that suits their deployment. Updated the docstring to note that the timeout should comfortably exceed retry_interval when both are set.
|
@Kludex another attempt, no external managers or anything this time. |
|
Same thing for |
| session_idle_timeout: Optional idle timeout in seconds for stateful sessions. | ||
| If set, sessions that receive no HTTP requests for this | ||
| duration will be automatically terminated and removed. | ||
| When retry_interval is also configured, ensure the idle | ||
| timeout comfortably exceeds the retry interval to avoid | ||
| reaping sessions during normal SSE polling gaps. | ||
| Default is None (no timeout). A value of 1800 | ||
| (30 minutes) is recommended for most deployments. |
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.
Fill 120 characters, and 4 padding from the above line, please.
| session_idle_timeout: Optional idle timeout in seconds for stateful sessions. | |
| If set, sessions that receive no HTTP requests for this | |
| duration will be automatically terminated and removed. | |
| When retry_interval is also configured, ensure the idle | |
| timeout comfortably exceeds the retry interval to avoid | |
| reaping sessions during normal SSE polling gaps. | |
| Default is None (no timeout). A value of 1800 | |
| (30 minutes) is recommended for most deployments. | |
| session_idle_timeout: Optional idle timeout in seconds for stateful sessions. | |
| if set, sessions that receive no HTTP requests for this | |
| duration will be automatically terminated and removed. | |
| When retry_interval is also configured, ensure the idle | |
| timeout comfortably exceeds the retry interval to avoid | |
| reaping sessions during normal SSE polling gaps. | |
| Default is None (no timeout). A value of 1800 | |
| (30 minutes) is recommended for most deployments. |
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.
I was hoping for us to not have this issue based folder, and instead have a structured based on the feature set itself/project structure.
A lot of the tests that AI creates seems unnecessary.
| await manager.handle_request(_make_scope(), _mock_receive, _make_send(sent)) | ||
| session_id = _extract_session_id(sent) | ||
|
|
||
| await anyio.sleep(0.3) |
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.
Please review your own test suite. And drop sleeps.
Summary
Adds a
session_idle_timeoutparameter toStreamableHTTPSessionManagerthat enables automatic cleanup of idle sessions, fixing the memory leak described in #1283.Motivation and Context
Sessions created via
StreamableHTTPSessionManagerpersist indefinitely in_server_instanceseven after clients disconnect without sending DELETE. Over time this leaks memory. This was reported in #1283 and originally addressed in #1159 by @hopeful0 — this PR reworks that approach.Key design decisions:
CancelScopewith a deadline inside each session'srun_servertask. When the deadline passes,app.run()is cancelled and the session cleans up. No background tasks needed — each session manages its own lifecycle.retry_interval(SSE polling) is configured, the effective timeout is at leastretry_interval_seconds * 3to avoid reaping sessions that are simply between polling reconnections.terminate()on the transport is now idempotent (early return if already terminated).None(no timeout, fully backwards compatible). Docstring recommends 1800s (30 min) for most deployments.How Has This Been Tested?
12 tests in
tests/issues/test_1283_idle_session_cleanup.py.All existing tests pass unchanged.
Breaking Changes
None.
session_idle_timeoutdefaults toNone(no timeout).Types of changes
Checklist
Additional context
Based on the approach from PR #1159 by @hopeful0, reworked to use cancel scope deadlines instead of transport-level timeout logic.
Closes #1283