gendesign/tradein-mvp/backend/tests/test_3412_browser_init_reaps_zombies.py
bot-backend 30d40e5747
All checks were successful
CI Trade-In / changes (pull_request) Successful in 19s
CI / changes (pull_request) Successful in 40s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Successful in 2m0s
CI Trade-In / backend-tests (pull_request) Successful in 8m5s
Сайдкар МЕРЫ: не больше трёх живых браузеров и никаких зомби-процессов (#3412)
Инстанс camoufox поднимался на поставщика и не закрывался никогда: пять
поставщиков давали пять вечных браузеров в контейнере с mem_limit 2560m. Прод
15.09-17.09: 5 живых простояли 2.4 ч прямо перед резким рестартом 16.09 19:08;
медиана working_set 1494 МиБ при 3 живых, 1956 при 4, 2108 при 5.

Потолок BROWSER_MAX_INSTANCES (по умолчанию 3) проверяется в _launch_browser,
через который идут все запуски, включая фоновый retry. На потолке закрывается
простаивающий инстанс другого поставщика: без context'а первым, по давности
использования внутри класса. Занятый лок не трогается, если закрыть некого,
запуск идёт сверх потолка с предупреждением. Слот резервируется на время
запуска. _close_browser снимает инстанс со словарей до первого await и больше
не сбрасывает пейсинг: это делают только собственный relaunch и смена прокси,
как раньше. Четыре дефекта ревью ветки fix/3412-cian-instance-relaunch
закрыты тестами, каждый краснеет при снятии своей части фикса.

init: true у сервиса browser: PID 1 был python server.py и не собирал
осиротевших детей закрытого браузера; прод 17.09 — 2296 процессов в Z за 14 ч.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 15:04:34 +05:00

24 lines
1.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#3412: у tradein-browser PID 1 — init, который собирает осиротевших детей camoufox.
Без `init: true` PID 1 контейнера — `python server.py`; дочерние процессы закрытого
браузера переходят к нему и остаются зомби (прод 17.09.2026: 2296 процессов в Z за 14 ч).
Проверка по значению: разобранный compose, сервис с образом tradein-browser.
"""
from pathlib import Path
import yaml
_COMPOSE = Path(__file__).resolve().parents[2] / "docker-compose.prod.yml"
def test_browser_service_runs_under_init() -> None:
services = yaml.safe_load(_COMPOSE.read_text())["services"]
browser = {
name: svc
for name, svc in services.items()
if "gendesign-tradein-browser" in svc.get("image", "")
}
# Контроль разбора: пустой словарь дал бы зелёный тест ни о чём.
assert set(browser) == {"browser"}, sorted(browser)
assert browser["browser"].get("init") is True