-
Notifications
You must be signed in to change notification settings - Fork 667
fix(v1,serve): discard delivered intercepts; trim worker arenas at heartbeat cadence #1610
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -224,6 +224,18 @@ def rollout_queue(self, rollout_key: str) -> asyncio.Queue[str]: | |
| def get_request(self, request_id: str) -> ConfigData: | ||
| return cast(ConfigData, self.server.intercepts[request_id]) | ||
|
|
||
| def discard_request(self, request_id: str) -> None: | ||
| """Drop a delivered intercept from the server's per-request store. | ||
|
|
||
| Each intercept retains the raw request body — the full message | ||
| history including in-sandbox base64 screenshots — and the server | ||
| only sweeps them at rollout unregister, so without per-delivery | ||
| discard a long browser rollout holds every turn's request body | ||
| simultaneously (~74% of env-worker memory measured). The HTTP | ||
| handler keeps its own local reference, so delivery is unaffected. | ||
| """ | ||
| self.server.intercepts.pop(request_id, None) | ||
|
|
||
| def request_context( | ||
| self, request_id: str, request: ConfigData | ||
| ) -> ModelRequestContext: | ||
|
|
@@ -450,14 +462,17 @@ async def forward_request( | |
| state._set_error(error_info(e)) | ||
| raise | ||
| finally: | ||
| if bool(request.get("stream")): | ||
| if request.get("protocol") != "openai_chat_completions": | ||
| raise NotImplementedError( | ||
| "Streaming interception is currently supported for OpenAI Chat Completions." | ||
| ) | ||
| await synthesize_stream(request, response, error) | ||
| else: | ||
| deliver_response(request, response, error) | ||
| try: | ||
| if bool(request.get("stream")): | ||
| if request.get("protocol") != "openai_chat_completions": | ||
| raise NotImplementedError( | ||
| "Streaming interception is currently supported for OpenAI Chat Completions." | ||
| ) | ||
| await synthesize_stream(request, response, error) | ||
| else: | ||
| deliver_response(request, response, error) | ||
| finally: | ||
| endpoint.discard_request(request_id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an intercepted request has Useful? React with 👍 / 👎. |
||
|
|
||
|
|
||
| def normalize_endpoint_prompt(request: ConfigData) -> Messages: | ||
|
|
||
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.
Every
EnvWorkeralready starts theconfigure_runtime_native_threads()daemon trim loop from_cap_native_threads()during construction, so this adds a second trim path that runs synchronously on the asyncio event-loop thread. Releasing the GIL does not let this same event loop continue processing requests or heartbeats whilemalloc_trim(0)is executing (or waiting on allocator locks held by the daemon trim), so on the large fragmented heaps this targets it can introduce exactly the worker lag/heartbeat delays the stats loop is meant to report; rely on the existing background trim or offload this call instead.Useful? React with 👍 / 👎.