Problema del patrón Singleton en el navegador Playwright
Resumen rápido: cuando se utiliza un gestor de navegador implementado como singleton en toda la aplicación, todas las peticiones comparten la misma instancia de navegador. Si una primera petición lanza el navegador con headless false y una petición posterior solicita headless true mientras la instancia anterior sigue activa, la petición posterior puede recibir la instancia ya lanzada con headless false. El ajuste headless se fija al arrancar el proceso del navegador y no puede cambiarse en caliente.
Cómo ocurre paso a paso: al cargar el módulo se crea una sola instancia, por ejemplo const playwrightManager = new PlaywrightBrowserManager(); esa instancia mantiene this.browser y this.context. Escenario 1 primera petición: launchBrowser({ headless: false }) crea BrowserInstance1 con headless false y lo devuelve. Escenario 2 segunda petición dos segundos después: launchBrowser({ headless: true }) comprueba this.browser, la ve conectada y la reutiliza, porque la lógica de reutilización solo mira si existe y está conectada. El resultado es que la segunda petición recibe BrowserInstance1 con headless false, aunque solicitó headless true. Esto sucede porque no existe un método para cambiar headless en una instancia de navegador ya lanzada; headless está fijado en el proceso del navegador desde su lanzamiento, por ejemplo const browser = await chromium.launch({ headless: false }); y no hay browser.setHeadless(true) disponible.
Fragmento de la lógica problemática: si this.browser existe y this.browser.isConnected() la implementación antigua devolvía la instancia si coincidía el valor actual de headless, y en algunos casos devolvía la vieja instancia aun cuando los ajustes diferían. Eso provoca comportamientos inesperados y errores difíciles de depurar en entornos concurrentes.
Soluciones prácticas y alternativas
1 Cerrar y relanzar cuando cambian los ajustes: detectar que el parámetro headless solicitado no coincide con el de la instancia activa, cerrar la instancia actual y lanzar una nueva con los ajustes deseados. Esto garantiza que el proceso del navegador respete la configuración solicitada pero implica coste de rendimiento al relanzar.
2 No usar singleton para la gestión del navegador por petición: crear una nueva instancia de PlaywrightBrowserManager por cada petición concurrente. Cada manager mantiene su this.browser y this.context independientes, evitando que una petición afecte a otra. Esta estrategia es la más sencilla y evita fugas de configuración cuando las peticiones requieren distintos parámetros.
3 Usar una arquitectura basada en pool o cache por clave: mantener varias instancias indexadas por la configuración clave, por ejemplo key = headless true o false y otros parámetros relevantes. Al solicitar un navegador se devuelve una instancia del pool que coincida con la configuración; si no existe se crea y se añade al pool. Esta opción equilibra reutilización y compatibilidad con distintas configuraciones.
¿Por qué separar instancias lo arregla Todo se reduce a evitar compartir this.browser entre peticiones. Si cada petición obtiene su propio gestor y su propio navegador no hay posibilidad de reutilizar accidentalmente una instancia con ajustes distintos. Además permite controlar el ciclo de vida del navegador por petición.
Buenas prácticas recomendadas
- Comprobar explícitamente los parámetros de configuración antes de reutilizar una instancia y cerrar la existente si hay discrepancia.
- Preferir instancias aisladas por petición si las configuraciones pueden variar mucho entre usuarios o flujos concurrentes.
- Implementar un pool con límites y tiempo de vida para equilibrar rendimiento y flexibilidad.
Sobre Q2BSTUDIO y servicios relacionados
En Q2BSTUDIO somos una empresa de desarrollo de software y aplicaciones a medida especializada en soluciones empresariales. Ofrecemos desarrollo de software a medida, aplicaciones a medida, servicios de inteligencia artificial y seguridad avanzada. Si buscas crear una solución que evite problemas de concurrencia en gestores de recursos como navegadores automatizados, podemos ayudarte a diseñar una arquitectura robusta y escalable. Con experiencia en proyectos de desarrollo de aplicaciones y software a medida y en servicios de inteligencia artificial, ofrecemos también ciberseguridad, servicios cloud aws y azure, servicios inteligencia de negocio, ia para empresas, agentes IA y soluciones con power bi para mejorar la toma de decisiones.
Conclusión
El patrón singleton puede causar que una instancia previa del navegador persista y devuelva valores antiguos cuando las peticiones requieren configuraciones distintas. La solución adecuada depende del caso de uso: cerrar y relanzar, instancias por petición o un pool con claves. En todos los casos recuerda que el modo headless se define al lanzar el proceso del navegador y no se puede cambiar sin relanzarlo. Si necesitas asistencia para diseñar la solución más adecuada para tu arquitectura, en Q2BSTUDIO podemos asesorarte y desarrollar la implementación óptima para tus necesidades de automatización, seguridad y escalabilidad.



