• Stefy Lanza (nextime / spora )'s avatar
    front: an in-flight request that leaks freezes the install, so stop leaking one (v0.3.27) · cbd51a4a
    Stefy Lanza (nextime / spora ) authored
    coderai_engine_inflight / coderai_requests_active are load-bearing: the hourly
    autoupgrade's idle guard reads them to decide whether a restart is safe, and with
    MAX_DEFERRALS=0 a non-zero count makes it SKIP for ever. So one request counted
    in and never out silently stops a host taking upgrades, and the only symptom is
    a version that stops moving.
    
    Observed on the Digesta orchestrator today: the gauge read 13 against two real
    requests, the 09:01 tick logged "SKIP: 7 piece(s) of work in progress" and left
    the image alone, and only a manual restart cleared it.
    
    The structural leak is in the streaming proxy path. Starlette awaits a
    response's background task only AFTER the body is sent --
    `await self.stream_response(send)` then `await self.background()` -- so when the
    client disconnects mid-stream the send raises, the exception propagates, and
    `BackgroundTask(_release)` never runs. The relay generator's `finally` DOES run
    in that case (Starlette closes the iterator) but not when the body is returned
    without streaming, so both now call `_release`, which is idempotent via a flag.
    
    `exit_request` is idempotent per rid as well, and that is required rather than
    decorative: two release paths firing for one request would otherwise decrement
    an UNRELATED in-flight request, and the count would under-report real work --
    worse than over-reporting, because then a restart lands during a request.
    
    Every request is now timestamped, not just the inference ones that carry `meta`.
    Without that a leaked non-inference request was invisible as well as
    unreleasable: the count said 13 and the Tasks page showed nothing, which is how
    this went unnoticed.
    
    And a reaper underneath all of it (`server.inflight_max_age_s`, default 3600,
    0 disables), called from the two places that ASK whether anything is in flight:
    
      * the /metrics scrape, because that is the exact moment a stale count does its
        damage -- the scrape that would report a lie is the right place to correct
        it, not to hope somebody notices;
      * the supervisor's drain wait, which would otherwise sit out the whole grace
        period for a request that finished an hour ago.
    
    An hour, not a minute: a cold RunPod pod can make a single OCR page take 14
    minutes, and reaping a live request would be a worse bug than the one being
    fixed. Training is unaffected -- it is tracked as a JOB and the request that
    starts it returns at once.
    
    NOT fixed here, noted for later: `_proxy_passthrough` has the same
    BackgroundTask-only release for the system worker. It never calls
    enter_request, so it cannot leak the gauge -- it leaks an httpx stream, which is
    a smaller and separate problem.
    
    tests/test_front_inflight_leak.py: 14 tests, including double-release, late
    release after a reap, thread safety, and the source invariants for the two
    release paths. 299 passed across the front/metrics/registry/config/admin
    selection; the 9 failures are pre-existing (broker_config x5, broker_streaming,
    studio_composed_surfaces, whisper_server x2) and touch no file changed here.
    Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01PxYHWbCAjjjD7A1rhFKtaW
    cbd51a4a
Name
Last commit
Last update
..
conftest.py Loading commit data...
test_admin_auth.py Loading commit data...
test_admin_forward_auth.py Loading commit data...
test_admin_remote_ui.py Loading commit data...
test_audio_ml_backends.py Loading commit data...
test_audio_ml_endpoints.py Loading commit data...
test_autoupgrade.py Loading commit data...
test_autoupgrade_recovers_a_down_server.py Loading commit data...
test_autoupgrade_sees_training.py Loading commit data...
test_broker_config.py Loading commit data...
test_broker_dispatch.py Loading commit data...
test_broker_protocol.py Loading commit data...
test_broker_shutdown.py Loading commit data...
test_broker_streaming.py Loading commit data...
test_burst_placement.py Loading commit data...
test_character_studio_fetch.py Loading commit data...
test_cluster.py Loading commit data...
test_compose.py Loading commit data...
test_forward_auth_peer_trust.py Loading commit data...
test_front_api_auth.py Loading commit data...
test_front_inflight_leak.py Loading commit data...
test_front_ocr_swap_gate.py Loading commit data...
test_image_has_c_compiler.py Loading commit data...
test_longcat_avatar_layout.py Loading commit data...
test_longcat_bsa.py Loading commit data...
test_longcat_cancellable.py Loading commit data...
test_longcat_checkpoint_resolve.py Loading commit data...
test_longcat_component_quant.py Loading commit data...
test_longcat_config_ui.py Loading commit data...
test_longcat_external_training.py Loading commit data...
test_longcat_int8_load.py Loading commit data...
test_longcat_lora.py Loading commit data...
test_longcat_orchestration.py Loading commit data...
test_longcat_packaging.py Loading commit data...
test_longcat_placement.py Loading commit data...
test_longcat_progress.py Loading commit data...
test_longcat_prompt_cache.py Loading commit data...
test_longcat_quantize.py Loading commit data...
test_longcat_scale.py Loading commit data...
test_longcat_tasks.py Loading commit data...
test_longcat_variants.py Loading commit data...
test_longcat_vendored_source.py Loading commit data...
test_longcat_venv_env.py Loading commit data...
test_longcat_vram_estimate.py Loading commit data...
test_longcat_worker.py Loading commit data...
test_manual_multimodal_test_client.py Loading commit data...
test_model_scan_cache.py Loading commit data...
test_ocr_chandra.py Loading commit data...
test_ocr_fanout.py Loading commit data...
test_ocr_language.py Loading commit data...
test_ocr_olmocr.py Loading commit data...
test_ocr_served_model.py Loading commit data...
test_ocr_token_trace.py Loading commit data...
test_ocr_unreadable_and_dpi.py Loading commit data...
test_ocr_vram_share_and_fallback.py Loading commit data...
test_olmocr_pod_tls.py Loading commit data...
test_oom_priority.py Loading commit data...
test_pod_log_drain.py Loading commit data...
test_proxy_logprobs.py Loading commit data...
test_remote_execution.py Loading commit data...
test_runpod_client_scale.py Loading commit data...
test_runpod_fleet_status.py Loading commit data...
test_runpod_global_volume.py Loading commit data...
test_runpod_ocr_remotization.py Loading commit data...
test_runpod_placement.py Loading commit data...
test_runpod_pod_extra_args.py Loading commit data...
test_runpod_reaper_grace.py Loading commit data...
test_runpod_scale_down.py Loading commit data...
test_runpod_schedule_region_spend.py Loading commit data...
test_runpod_warmup.py Loading commit data...
test_studio_composed_surfaces.py Loading commit data...
test_surya_runpod_fixes.py Loading commit data...
test_township_api_key.py Loading commit data...
test_township_clip_geometry.py Loading commit data...
test_township_longcat.py Loading commit data...
test_township_page_js.py Loading commit data...
test_township_templates.py Loading commit data...
test_township_video_dataset.py Loading commit data...
test_upgrade_launcher.py Loading commit data...
test_video_as_b64_scope.py Loading commit data...
test_video_geometry.py Loading commit data...
test_vllm_share_self_tuning.py Loading commit data...
test_vram_releasers.py Loading commit data...
test_weight_stores.py Loading commit data...
test_whisper_server_local_models.py Loading commit data...