Bladeren bron

re-initialize browser connection when it's lost because of no activity

alexchenzl 7 maanden geleden
bovenliggende
commit
d1f276420a
2 gewijzigde bestanden met toevoegingen van 37 en 4 verwijderingen
  1. 14 0
      src/nanobrowser/lib/agent/executor.py
  2. 23 4
      src/nanobrowser/lib/browser/manager.py

+ 14 - 0
src/nanobrowser/lib/agent/executor.py

@@ -111,6 +111,19 @@ class Executor:
         """Set a flag to stop the current task execution now"""
         self._agent_context.stop_task_now = True
             
+    async def _ensure_browser_is_connected(self):
+        # Sometimes, error "Target page, context or browser has been closed" is thrown when calling get_current_page_info()
+        # This happens when there's no activity on the browser for a while
+        try:
+           _info = await self._browser_context.get_current_page_info()
+        except Exception as e:
+            logger.error(f"Lost connection to browser: {str(e)}")
+            await self._browser_manager.reinitialize()
+        finally:
+            self._browser_context = await self._browser_manager.get_browser_context()
+            self._agent_context.browser_context = self._browser_context
+            
+
     async def run(self, task: str, task_id: str, max_steps: Optional[int] = 100, tab_id: Optional[str] = None):
         """
         Run a task
@@ -140,6 +153,7 @@ class Executor:
             self._current_task_id = task_id
         
         try:
+            await self._ensure_browser_is_connected()
             # Start task execution in background
             await self._execute_task(task, max_steps, tab_id)
         finally:

+ 23 - 4
src/nanobrowser/lib/browser/manager.py

@@ -103,6 +103,24 @@ class PlaywrightManager:
 
             self.__async_initialize_done = True
 
+    async def reinitialize(self):
+        """
+        Reinitialize the browser and browser context, useful when the browser connection is lost.
+        """
+        async with self.__init_lock:
+
+            try:            
+                if self._playwright is not None:
+                    await self._playwright.stop()
+                    self._playwright = None
+            except Exception as e:
+                logger.warning(f"Failed to stop playwright: {str(e)}")
+
+            self.__async_initialize_done = False
+            self._browser = None
+            self._browser_context = None
+
+        await self.async_initialize()
 
     async def _connect_to_browser(self):
         """
@@ -214,14 +232,16 @@ class PlaywrightManager:
             raise e
 
 
-    async def get_browser_context(self):
+    async def get_browser_context(self, refresh: bool = False):
         """
         Returns the existing browser context, or creates a new one if it doesn't exist.
+        If refresh is True, the browser context will be refreshed.
         """
-        if self._browser_context is None:
+        if self._browser_context is None or refresh:
+            logger.debug("Creating new browser context")
             await self.create_browser_context()
         return self._browser_context
-
+    
 
     async def close(self):
         """
@@ -252,6 +272,5 @@ class PlaywrightManager:
             self._browser = None
             self._browser_context = None
             self._chrome_launcher = None
-            self._playwright = None
             self.__async_initialize_done = False