fix: matar los chromium que el MCP lanza para cerrar el leak de RAM
El pool nunca guardaba el PID del Chrome lanzado por browser_launch, así que closeAll() y drop() cerraban con CdpClose(c, 0): solo soltaban el WebSocket y dejaban el proceso chromium vivo y huérfano (~789 MiB RSS cada uno). Llamadas repetidas a browser_launch acumulaban instancias sin límite hasta saturar la RAM (apagón del 06/06/2026, ~35 chromium huérfanos). Cambios: - pool.go: el pool registra el PID lanzado por puerto (mapa `pids`) con setPID/getPID/clearPID/launchedCount. drop() y closeAll() matan el grupo de proceso completo (CdpClose con pid real) SOLO si el PID está registrado, es decir, si lo lanzó el MCP. Un Chrome externo sin PID registrado (el navegador diario del usuario en 9222) nunca se mata: pid=0 solo cierra el WebSocket. Nuevo releaseConn() suelta únicamente el WebSocket preservando el PID, para la reconexión interna (no debe matar el navegador). - tools_session.go: handleLaunch registra el PID devuelto por ChromeLaunch (setPID); es idempotente por puerto (reusa el Chrome ya lanzado), pasa ReuseExisting=true para no duplicar un Chrome ya vivo en el puerto, y aplica un tope duro de 4 instancias (maxLaunchedChromes) devolviendo un error de tool al superarlo. browser_disconnect ahora mata el Chrome propio. - main.go: handler SIGTERM/SIGINT que llama closeAll antes de salir (los defers no corren al recibir señal). El retry de withConn usa releaseConn en vez de drop para no matar el Chrome al reconectar. - pool_test.go: tests lógicos sin Chrome (cap, idempotencia, ciclo de PID, drop). - pool_e2e_test.go: tests con Chrome real (gate BMCP_E2E=1) — golden (3 launch → closeAll → 0 huérfanos), dedup mismo puerto, y salvaguarda propio-vs-externo. - app.md: e2e_checks (build, unit, leak_no_orphans) + growth log + bump a 0.5.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,9 +2,20 @@
|
||||
name: browser_mcp
|
||||
lang: go
|
||||
domain: infra
|
||||
version: 0.4.0
|
||||
version: 0.5.0
|
||||
description: "Servidor MCP que expone control total del navegador via CDP (40 tools: navegación, DOM, cookies, iframes, teclado/scroll, diálogos, estado de sesión, selección determinista de pestaña, lectura compacta texto/AX + bucle percibir→actuar por #ref con auto-observe, incluyendo find-ref-by-text) reusando funciones del dominio browser del registry con un pool de conexiones CDP vivas. Por defecto opera sobre un Chrome aislado (puerto 9333) separado del navegador diario."
|
||||
tags: [mcp, browser, cdp, automation, scraping]
|
||||
e2e_checks:
|
||||
- id: build
|
||||
cmd: "cd projects/web_scraping/apps/browser_mcp && go build -o browser_mcp ."
|
||||
timeout_s: 120
|
||||
- id: unit
|
||||
cmd: "cd projects/web_scraping/apps/browser_mcp && go test -count=1 ./..."
|
||||
timeout_s: 120
|
||||
- id: leak_no_orphans
|
||||
cmd: "cd projects/web_scraping/apps/browser_mcp && go test -c -o /tmp/bmcp_e2e.test . && systemd-run --user --quiet --collect --unit=bmcp_e2e_ci --wait -p Type=oneshot --setenv=BMCP_E2E=1 -p StandardOutput=journal /tmp/bmcp_e2e.test -test.run TestE2E -test.v"
|
||||
timeout_s: 180
|
||||
severity: warning
|
||||
uses_functions:
|
||||
- chrome_launch_go_browser
|
||||
- cdp_connect_go_browser
|
||||
@@ -230,6 +241,15 @@ Funciones del dominio `browser` que NO se exponen como tools en esta versión, c
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v0.5.0 (2026-06-06) — Fix del leak de RAM (chromium huérfanos, apagón 06/06/2026). El pool
|
||||
ahora registra el PID del Chrome que lanzó por puerto (`pids` map + setPID/getPID/clearPID/
|
||||
launchedCount). `browser_disconnect` (drop) y el shutdown (closeAll) matan el grupo de proceso
|
||||
completo SOLO si el PID está registrado (lo lanzó el MCP) — un Chrome externo (navegador diario
|
||||
en 9222) nunca se mata, solo se cierra el WebSocket. `browser_launch` es idempotente por puerto,
|
||||
reusa un Chrome ya vivo (`ChromeLaunch.ReuseExisting`, pid 0 = no relanza) y aplica un tope duro
|
||||
de 4 instancias. Handler SIGTERM/SIGINT en main.go llama closeAll (los defers no corren con
|
||||
señal). `withConn` retry usa `releaseConn` (suelta solo el WS) en vez de drop. Tests: pool_test.go
|
||||
(lógicos) + pool_e2e_test.go (Chrome real, gate BMCP_E2E=1). e2e_checks añadidos.
|
||||
- v0.3.0 (2026-06-06) — Cierre del bucle percibir→actuar. Nuevas tools `dom_click_ref`,
|
||||
`dom_type_ref`, `dom_hover_ref`: actúan sobre el `#ref` (backendDOMNodeId estable) del
|
||||
outline de `page_perceive` con humanización por defecto (Bézier+jitter) y auto-observe
|
||||
|
||||
Reference in New Issue
Block a user