---
name: playwright-executor-fix
description: 修复 Windows 平台上 Playwright 执行器在 FastAPI asyncio 环境中无法启动的问题
metadata:
  type: feedback
  created: 2026-07-11
---

# Playwright 执行器 Windows 兼容性修复

## 问题描述

在 Windows 系统上，Playwright 异步 API (`async_playwright`) 在 FastAPI 的 asyncio 事件循环中无法正常工作。

**错误信息：**
```
NotImplementedError
```

**根本原因：**
Windows 上的 asyncio 默认使用 `SelectorEventLoop`，而 Playwright 的异步启动需要创建子进程管道，这在 `SelectorEventLoop` 上会抛出 `NotImplementedError`。即使使用 `ProactorEventLoop`，Playwright 也会检测到自己在 asyncio 循环中运行并拒绝同步 API。

## 解决方案

1. **将 Playwright 执行器从异步 API (`async_playwright`) 改为同步 API (`sync_playwright`)**
   - 文件：`backend/app/executors/playwright_executor.py`
   - 所有方法从 `async def` 改为 `def`
   - 移除所有 `await` 调用

2. **在线程池中执行同步 Playwright 代码**
   - 文件：`backend/app/services/execution_service.py`
   - 使用 `loop.run_in_executor()` 在独立线程中运行同步执行器
   - 避免 Playwright 检测到 asyncio 循环环境

## 代码变更

### 1. playwright_executor.py

```python
# 之前（异步）
from playwright.async_api import async_playwright

async def start(self):
    self._playwright = await async_playwright().start()
    self._browser = await self._playwright.chromium.launch(...)

# 之后（同步）
from playwright.sync_api import sync_playwright

def start(self):
    self._playwright = sync_playwright().start()
    self._browser = self._playwright.chromium.launch(...)
```

### 2. execution_service.py

```python
# 之前（直接调用）
result = executor.execute_case(case=case.to_dict(), callback=step_callback)

# 之后（线程池执行）
loop = asyncio.get_event_loop()
def run_case_sync(case_dict, callback):
    return executor.execute_case(case=case_dict, callback=callback)

result = await loop.run_in_executor(None, run_case_sync, case.to_dict(), step_callback)
```

## 验证结果

- ✅ Playwright 执行器可以正常启动 Chromium 浏览器
- ✅ 测试步骤可以正常执行
- ✅ 截图功能正常工作
- ✅ 步骤失败后后续步骤正确标记为 skipped
- ✅ 执行结果正确保存到数据库

## Why

Playwright 的异步 API 在 Windows 上与 FastAPI 的 asyncio 事件循环不兼容。

## How to apply

当遇到类似"执行器启动失败"错误时，检查是否在 Windows 环境下运行，并确保同步 Playwright API 在独立线程中执行。

[[playwright]]
[[windows-compatibility]]
