fix(OPEN-11984): bound background-publish queue to stop unbounded memory growth - #661
Merged
Merged
Conversation
…ded memory growth A slow or unreachable Openlayer backend let traces pile up in the ThreadPoolExecutor's unbounded work queue since each queued item holds the full step inputs/outputs, causing traced FastAPI services to OOM under sustained load. Cap the number of in-flight/queued traces via a semaphore (background_publish_max_queue_size, default 100) and drop with a warning once full instead of buffering indefinitely. Also fix _current_trace ContextVar never being reset after a root trace completes (only _current_step was reset), which could pin a stale Trace object in memory longer than necessary.
gustavocidornelas
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@trace, but is stable without tracing (OPEN-11984)._handle_trace_completionsubmits every completed trace to a fixed 4-workerThreadPoolExecutorfor background publishing. That executor's internal work queue is unbounded, so if the Openlayer backend is slow/unreachable, queuedTraceobjects (each holding full step inputs/outputs) accumulate in memory without limit.threading.Semaphoresized by a newbackground_publish_max_queue_sizeconfig knob (default 100, configurable viainit()). Once the cap is hit, new traces are dropped with a warning log instead of buffering indefinitely._current_traceContextVar was.set()at the start of every root trace but never.reset()(unlike_current_step), which could pin a staleTraceobject in memory longer than necessary. Now captures a token and resets it via the existing_safe_reset_contextvarhelper across all three code paths (plain functions, sync generators, async generators).Test plan
ruff checkcleanpytest tests/test_tracer_configuration.py tests/test_tracing_core.py— 57/57 passed, run 3x for flakinessbackground_publish_max_queue_size=2, and releases correctly on completionget_current_trace()returnsNoneafter a root trace completes (previously returned the stale trace)-k trac(missingopenai/litellmtest deps, and generator-test cross-contamination under-n0) are pre-existing onmainand unrelated to this changeCloses OPEN-11984.
🤖 Generated with Claude Code