fix: add max retry limit to _get_page_content to prevent infinite loop

Both _get_page_content and _get_async_page_content use a while-True
loop that retries page.content() on PlaywrightError with no upper
bound. If the page is in a permanently broken state (crashed tab,
closed context), this loops forever and hangs the process.

Replace with a bounded for-loop (default 10 retries = 5s), returning
an empty string if all attempts fail. This preserves the existing
retry behavior for the transient Windows issue (playwright#16108)
while preventing hangs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
haosenwang1018
2026-03-15 17:53:23 +08:00
parent c7f0db912c
commit d3c251c1ab
+8 -8
View File
@@ -187,34 +187,34 @@ class ResponseFactory:
return history
@classmethod
def _get_page_content(cls, page: SyncPage) -> str:
def _get_page_content(cls, page: SyncPage, max_retries: int = 10) -> str:
"""
A workaround for the Playwright issue with `page.content()` on Windows. Ref.: https://github.com/microsoft/playwright/issues/16108
:param page: The page to extract content from.
:param max_retries: Maximum number of retry attempts before returning empty string.
:return:
"""
while True:
for _ in range(max_retries):
try:
return page.content() or ""
except PlaywrightError:
page.wait_for_timeout(500)
continue
return "" # pyright: ignore
return ""
@classmethod
async def _get_async_page_content(cls, page: AsyncPage) -> str:
async def _get_async_page_content(cls, page: AsyncPage, max_retries: int = 10) -> str:
"""
A workaround for the Playwright issue with `page.content()` on Windows. Ref.: https://github.com/microsoft/playwright/issues/16108
:param page: The page to extract content from.
:param max_retries: Maximum number of retry attempts before returning empty string.
:return:
"""
while True:
for _ in range(max_retries):
try:
return (await page.content()) or ""
except PlaywrightError:
await page.wait_for_timeout(500)
continue
return "" # pyright: ignore
return ""
@classmethod
async def from_async_playwright_response(