From c115676e238f552bef3fcda3e812700ae2fa807b Mon Sep 17 00:00:00 2001 From: root Date: Tue, 29 Sep 2026 03:15:46 +0800 Subject: [PATCH] fix(browser): opening a session ignores ones another process already closed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The worker's adapter still held a session the api process had closed, so browser.navigate {siteId} from an agent run failed with "该站点/账号 已有未关闭的浏览器会话" (REAL-2 task 4). When the database has no live session for the profile, stale in-memory ones are marked closed before opening. Needs image rebuild. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/modules/browser/service.ts | 3 +++ apps/server/test/e2e/e14-vision.test.ts | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/browser/service.ts b/apps/server/src/modules/browser/service.ts index f8921f7d..36ae036d 100644 --- a/apps/server/src/modules/browser/service.ts +++ b/apps/server/src/modules/browser/service.ts @@ -677,6 +677,9 @@ export class BrowserService { } const budget = this.budgetFor(site, prow); const provider = this.providerFor(prow); + // 数据库里已没有未关闭的会话:本进程内存里同 profile 还开着的是别的进程关掉的,标关闭,否则适配器拒绝新开 + for (const m of await provider.listSessions()) + if (m.profileKey === profileKey && m.controller !== "closed") provider.setController(m.id, "closed"); await this.rateLimit(site); let res: Awaited>; try { diff --git a/apps/server/test/e2e/e14-vision.test.ts b/apps/server/test/e2e/e14-vision.test.ts index 9c1f84dd..d7020e25 100644 --- a/apps/server/test/e2e/e14-vision.test.ts +++ b/apps/server/test/e2e/e14-vision.test.ts @@ -354,7 +354,7 @@ describe.skipIf(!hasPg)("E14 视觉自动化闭环", () => { for (const l of ledger) expect((l.output as Any).modelImage).toBeNull(); }, 90_000); - it("另一个进程(api)在标签页被回收后重开,本进程(worker)按数据库换到新标签页", async () => { + it("多进程:api 重开被回收的标签页后 worker 换到新标签页;api 关闭会话后 worker 能重新打开", async () => { await open(ids.site, ids.provider, `${ORIGIN}/torrents.php`); const worker = new BrowserService(e.booted.ctx, svc.opts); const auto = { kind: "automation", holder: "agent:e14" } as const; @@ -368,5 +368,10 @@ describe.skipIf(!hasPg)("E14 视觉自动化闭环", () => { ); expect((await svc.view(sid)).currentTabId).not.toBe(old); await expect(snap(worker)).resolves.toMatchObject({ url: expect.stringContaining("/torrents.php") }); + // api 关闭会话后,worker 能按站点重新打开(不被内存里的旧会话挡住) + await svc.close(sid); + const again = await worker.open({ siteId: ids.site, providerId: ids.provider, url: `${ORIGIN}/torrents.php` }); + expect(again).not.toBe(sid); + await worker.close(again); }, 60_000); });