Files
fn_registry/functions/browser/chrome_launch.md
T
egutierrez 37aacfcfa9 feat(browser): chrome_launch ReuseExisting — guarda anti-duplicado de Chrome
Añade el campo ReuseExisting a ChromeLaunchOpts. Con ReuseExisting=true, si el
puerto CDP ya responde a una conexión TCP, ChromeLaunch NO lanza un Chrome nuevo
y devuelve (0, nil) para que el caller se adjunte al existente. Evita acumular
procesos chromium duplicados en el mismo puerto (cada uno ~789 MiB RSS), causa
del leak de RAM del browser_mcp.

Extrae el sondeo de puerto a dialCDP/cdpPortResponds (net.Dial con timeout), que
waitCDPReady ahora reutiliza en su bucle. Tests sin Chrome real (TestCdpPortResponds,
TestChromeLaunchReuseExisting) usando un net.Listener local como puerto ocupado.
Bump a 1.4.0 + growth log + gotchas en el .md (pid 0 = no es nuestro, no matar).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:06:45 +02:00

6.8 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
chrome_launch function go browser 1.4.0 impure func ChromeLaunch(opts ChromeLaunchOpts) (int, error) Lanza Google Chrome con remote debugging habilitado en el puerto indicado. En Linux nativo busca primero chromium/google-chrome/brave; en WSL2 busca chrome.exe primero. En WSL2+chrome.exe traduce UserDataDir a ruta Windows via wslpath e inyecta --remote-debugging-address=0.0.0.0. En Linux nativo setea Setpgid=true para crear grupo de proceso propio (permite matar el arbol completo con CdpClose). Espera hasta 15s a que el puerto CDP este listo. Retorna el PID del proceso.
chrome
cdp
browser
automation
wsl2
headless
navegator
linux
false error_go_core
fmt
net
os
os/exec
regexp
strings
syscall
time
name desc
opts opciones de lanzamiento: Port (defecto 9222), UserDataDir (defecto /tmp/chrome-cdp-profile en Linux, C:\Users<USER>\AppData\Local\fn-chrome-cdp-profile en WSL2+exe), Headless, ChromePath, ExtraArgs, KeepExtensions (si true no añade --disable-extensions, util para cargar extensiones del perfil), ProfileDirectory (selecciona el perfil con --profile-directory, ej: Default / Automation; vacío = no se pasa el flag), ReuseExisting (si true y el puerto CDP ya responde, no lanza Chrome nuevo y devuelve pid 0 — anti-duplicado)
int: PID del proceso Chrome lanzado, o 0 si ReuseExisting=true y ya había un Chrome vivo en el puerto true
TestIsWSL2
TestTranslateUserDataDirForWindows
TestIsWindowsExe
TestFindChrome
TestChromeLaunchAndConnect
TestCdpPortResponds
TestChromeLaunchReuseExisting
functions/browser/chrome_launch_test.go functions/browser/chrome_launch.go

Ejemplo

// Linux nativo: chromium se detecta automaticamente, grupo de proceso propio
pid, err := ChromeLaunch(ChromeLaunchOpts{
    Port:     9222,
    Headless: true,
})
if err != nil {
    log.Fatal(err)
}
defer CdpClose(nil, pid) // mata grupo completo (zygote, gpu, renderers)
// Linux nativo con extensiones del perfil cargadas
pid, err := ChromeLaunch(ChromeLaunchOpts{
    Port:           9222,
    UserDataDir:    "/home/user/.config/chromium",
    KeepExtensions: true,
})
// WSL2 → chrome.exe Windows: cero configuracion, todo automatico
pid, err := ChromeLaunch(ChromeLaunchOpts{})
if err != nil {
    log.Fatal(err)
}
// CDP listo en 127.0.0.1:9222 desde WSL2
conn, err := CdpConnect(9222)

Cuando usarla

Cuando necesites lanzar Chrome con CDP desde Go para automatizacion (scraping, tests, capturas). Usar antes de CdpConnect / CdpNavigate / CdpScreenshot. Funciona en Linux nativo y en WSL2 apuntando al chrome.exe de Windows.

Gotchas

  • Linux nativo — orden de busqueda: chromium > chromium-browser > google-chrome > google-chrome-stable > brave-browser. Los .exe son ultimo recurso en Linux nativo.
  • WSL2 + chrome.exe: la funcion detecta automaticamente WSL2 (/proc/version contiene "microsoft"/"WSL") y que el ejecutable es .exe. En ese caso:
    • UserDataDir vacio o con prefijo /tmp/ o /home/ se traduce via wslpath -w a ruta Windows. Por defecto: C:\Users\<USER>\AppData\Local\fn-chrome-cdp-profile.
    • Se inyecta --remote-debugging-address=0.0.0.0 para que Chrome sea accesible desde WSL2 vía 127.0.0.1:<port>.
  • Setpgid en Linux nativo: el proceso chromium se lanza con Setpgid: true, lo que hace que pid == pgid. Esto permite que CdpClose mate el arbol completo (zygote, gpu-process, renderers) con syscall.Kill(-pid, SIGKILL). NO aplica en WSL+Windows.
  • KeepExtensions: por defecto se añade --disable-extensions. Pasar KeepExtensions: true para omitir ese flag y mantener extensiones del perfil (útil con perfiles reales de usuario).
  • wslpath debe estar disponible (WSL2 desde Windows 10 1903+): se invoca como subproceso en modo WSL2+exe. Si falla, ChromeLaunch retorna error.
  • ProfileDirectory obligatorio con múltiples perfiles: sin --profile-directory, si el user-data-dir contiene varios perfiles (Default, Personal, Profile 1, Automation…) Chrome se queda atascado en el selector de perfil y no carga nada — el puerto CDP responde pero no hay perfil activo y las extensiones no se procesan. Pasar ProfileDirectory: "Default" (o el nombre exacto del subdirectorio) para evitarlo.
  • Chrome no cierra solo: el PID devuelto es el proceso Chrome. Usar CdpClose(nil, pid) para terminar el arbol de procesos. Quien lance debe guardar el pid; sin él, CdpClose(c, 0) solo cierra el WebSocket y deja Chrome huérfano (~789 MiB RSS cada uno). Acumular lanzamientos sin matar = leak de RAM.
  • Puerto ocupado: si el puerto ya está en uso por otra instancia de Chrome, waitCDPReady puede conectar al proceso previo. Usar puertos distintos por sesión, o pasar ReuseExisting: true para que la función NO lance un duplicado y devuelva pid 0 (el caller se adjunta al Chrome existente).
  • ReuseExisting + pid 0: con ReuseExisting: true un retorno (0, nil) significa "ya había un Chrome vivo en el puerto, no lancé otro". El caller NO debe registrar ni intentar matar ese pid 0; el proceso no es suyo (puede ser el navegador diario del usuario).

Notas

Busca Chrome en este orden (Linux nativo):

  1. chromium, chromium-browser, google-chrome, google-chrome-stable, brave-browser
  2. chrome.exe (ultimo recurso, normalmente no en PATH en Linux nativo)

Busca Chrome en este orden (WSL2):

  1. chrome.exe en PATH
  2. /mnt/c/Program Files/Google/Chrome/Application/chrome.exe
  3. /mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe
  4. binarios Linux como fallback

Los flags aplicados desactivan funcionalidades de red y actualizacion en segundo plano para entornos de automatizacion. En modo headless se agrega --headless=new --disable-gpu.

El struct ChromeLaunchOpts se define en el mismo archivo.

Capability growth log

  • v1.1.0 (2026-05-16) — auto-handle WSL2→Windows chrome.exe: translate user-data-dir via wslpath + inject --remote-debugging-address=0.0.0.0
  • v1.2.0 (2026-06-05) — Linux-first: reordena busqueda (chromium antes que chrome.exe) en Linux nativo; añade KeepExtensions; setea Setpgid=true en Linux para habilitar kill-by-group en CdpClose
  • v1.3.0 (2026-06-05) — añade ProfileDirectory / --profile-directory para seleccionar perfil dentro del user-data-dir (evita quedarse atascado en el selector cuando hay varios perfiles)
  • v1.4.0 (2026-06-06) — añade ReuseExisting: guarda anti-duplicado que devuelve (0, nil) sin lanzar cuando el puerto CDP ya responde. Extrae helper dialCDP/cdpPortResponds (sondeo TCP reutilizado por waitCDPReady). Cierra el leak de chromium huérfanos del browser_mcp (lanzamientos repetidos al mismo puerto)