From dbd061e119d0d504044898494cdff2ce9cfb5654 Mon Sep 17 00:00:00 2001 From: Linghong Date: Sat, 11 Jul 2026 10:26:38 +0000 Subject: [PATCH] Add cross_check lock so a locked lane ignores per-request cross_check=on The cpu-fast lane disables cross-check to fit a low-memory box, but a request could still send cross_check=on and override it, lazy-loading the HR-matting model and running the 2048 forward -> the exact OOM (worker SIGKILL -> 502) cpu-fast exists to avoid. BGFILTER_CROSS_CHECK=0 did not protect against this because the per-request form field wins. Add CrossCheckSettings.lock (default False). When set, PipelineManager resolves cross-check to the base value and ignores per-request overrides, so a locked off-lane silently honours cross_check=on as off -- no HR-matting load, no cross-check run, no error (200), and the response header reports "off". Enable it in cpu-fast.yaml (enabled: false, lock: true). Verified end-to-end: cross_check=on on the locked lane returns without loading the cross-checker. Co-Authored-By: Claude Opus 4.8 --- app.py | 3 ++- bgfilter/service.py | 19 +++++++++++++++++-- bgfilter/settings.py | 5 +++++ configs/cpu-fast.yaml | 2 ++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index ce814c0..af431c8 100644 --- a/app.py +++ b/app.py @@ -210,7 +210,8 @@ async def remove_background( normalized_color = _normalize_screen_color(screen_color) normalized_seg = _normalize_seg_model(seg_model) or _manager.default_seg_model normalized_cc = _normalize_cross_check(cross_check) - effective_cc = normalized_cc if normalized_cc is not None else _manager.cross_check_enabled + # Honors the lane lock (a locked cpu-fast box reports/runs "off" even on cross_check=on). + effective_cc = _manager.effective_cross_check(normalized_cc) rgb = _decode_image(await file.read()) diff --git a/bgfilter/service.py b/bgfilter/service.py index 29bb967..f7cb2cf 100644 --- a/bgfilter/service.py +++ b/bgfilter/service.py @@ -66,6 +66,20 @@ class PipelineManager: def cross_check_enabled(self) -> bool: return self._base.cross_check.enabled + def effective_cross_check(self, requested: bool | None) -> bool: + """Resolve the cross-check state for a request, honoring the lane lock. + + When ``cross_check.lock`` is set (e.g. the cpu-fast lane) the base default + is authoritative and a per-request override is ignored -- so a locked + off-lane never loads the HR-matting model or risks an OOM, and never errors + on a ``cross_check=on`` request. Otherwise the request value wins when + given, else the base default applies. + """ + base = self._base.cross_check + if base.lock: + return base.enabled + return requested if requested is not None else base.enabled + def _get_runner(self) -> ViTMatteRunner: if self._runner is None: with self._load_lock: @@ -135,8 +149,9 @@ class PipelineManager: self._base, screen_color=screen_color, seg_backend=seg_model, - # None = keep the service default; True/False = per-request override. - cross_check=cross_check, + # Honor the lane lock: a locked lane ignores the per-request override + # (a cpu-fast box never runs cross-check, even on cross_check=on). + cross_check=self.effective_cross_check(cross_check), ) runner = ( self._get_runner() diff --git a/bgfilter/settings.py b/bgfilter/settings.py index cedde26..ee28fa1 100644 --- a/bgfilter/settings.py +++ b/bgfilter/settings.py @@ -80,6 +80,11 @@ class CrossCheckSettings: # that chroma, segmentation and the primary matte all read as foreground; # already-soft wisps and dark hair are exempt by construction. enabled: bool = True + # Lock the cross-check state to ``enabled`` and ignore per-request overrides. + # A memory-constrained lane (e.g. cpu-fast) sets ``enabled: false, lock: true`` + # so a request with ``cross_check=on`` is silently honoured as off instead of + # loading the HR-matting model and risking an OOM. No error is raised. + lock: bool = False model_name: str = "ZhengPeng7/BiRefNet_HR-matting" input_size: int = 2048 # Reuse the cross-check forward as the segmentation mask: one HR-matting diff --git a/configs/cpu-fast.yaml b/configs/cpu-fast.yaml index 0ee16f6..bbbe838 100644 --- a/configs/cpu-fast.yaml +++ b/configs/cpu-fast.yaml @@ -29,3 +29,5 @@ segmentation: cross_check: enabled: false # no second-opinion HR-matting pass (the big cost/mem sink) + lock: true # ignore per-request cross_check=on so a request can't + # force the HR-matting load and OOM this low-memory lane