Skip to content

Commit a589291

Browse files
Revert "chore: implement local browser rendering /v1/session endpoint (#10220)" (#10250)
This reverts commit b02843f.
1 parent 93c4c26 commit a589291

File tree

9 files changed

+61
-444
lines changed

9 files changed

+61
-444
lines changed

.changeset/petite-paws-allow.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

fixtures/browser-rendering/src/playwright.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,6 @@ export default {
3232
const pText = await page.locator("p").first().textContent();
3333
return new Response(pText);
3434
}
35-
36-
case "disconnect": {
37-
const { sessionId } = await playwright.acquire(env.MYBROWSER);
38-
const browser = await playwright.connect(env.MYBROWSER, sessionId);
39-
// closing a browser obtained with playwright.connect actually disconnects
40-
// (it doesn's close the porcess)
41-
await browser.close();
42-
const sessionInfo = await playwright
43-
.sessions(env.MYBROWSER)
44-
.then((sessions) =>
45-
sessions.find((s) => s.sessionId === sessionId)
46-
);
47-
return new Response(
48-
sessionInfo.connectionId
49-
? "Browser not disconnected"
50-
: "Browser disconnected"
51-
);
52-
}
5335
}
5436

5537
let img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" });

fixtures/browser-rendering/src/puppeteer.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,6 @@ export default {
3232
const pText = await page.$eval("p", (el) => el.textContent.trim());
3333
return new Response(pText);
3434
}
35-
36-
case "disconnect": {
37-
const browser = await puppeteer.launch(env.MYBROWSER);
38-
const sessionId = browser.sessionId();
39-
await browser.disconnect();
40-
const sessionInfo = await puppeteer
41-
.sessions(env.MYBROWSER)
42-
.then((sessions) =>
43-
sessions.find((s) => s.sessionId === sessionId)
44-
);
45-
return new Response(
46-
sessionInfo.connectionId
47-
? "Browser not disconnected"
48-
: "Browser disconnected"
49-
);
50-
}
5135
}
5236

5337
let img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" });

fixtures/browser-rendering/test/index.spec.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,6 @@ describe("Local Browser", () => {
6262
`New paragraph text set by ${lib === "playwright" ? "Playwright" : "Puppeteer"}!`
6363
);
6464
});
65-
66-
it("Disconnect a browser, and check its session connection status", async () => {
67-
await expect(
68-
fetchText(
69-
`http://${ip}:${port}/?lib=${lib}&url=https://example.com&action=disconnect`
70-
)
71-
).resolves.toEqual(`Browser disconnected`);
72-
});
7365
});
7466
}
7567
});

packages/miniflare/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
"npx-import": "^1.1.4",
9797
"postal-mime": "^2.4.3",
9898
"pretty-bytes": "^6.0.0",
99-
"puppeteer": "22.8.2",
10099
"rimraf": "catalog:default",
101100
"source-map": "^0.6.1",
102101
"ts-dedent": "^2.2.0",

packages/miniflare/src/index.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ export class Miniflare {
851851
#workerOpts: PluginWorkerOptions[];
852852
#log: Log;
853853

854-
// key is the browser session ID, value is the browser process
854+
// key is the browser wsEndpoint, value is the browser process
855855
#browserProcesses: Map<string, ChildProcess> = new Map();
856856

857857
readonly #runtime?: Runtime;
@@ -1265,23 +1265,19 @@ export class Miniflare {
12651265
// workaround for CI environments, to avoid sandboxing issues
12661266
args: process.env.CI ? ["--no-sandbox"] : [],
12671267
});
1268-
const sessionId = crypto.randomUUID();
1269-
const browserProcess = browser.process();
1270-
browserProcess.on("exit", () => {
1271-
this.#browserProcesses.delete(sessionId);
1272-
});
12731268
const wsEndpoint = browser.wsEndpoint();
1274-
const startTime = Date.now();
1275-
this.#browserProcesses.set(sessionId, browserProcess);
1276-
response = Response.json({ wsEndpoint, sessionId, startTime });
1269+
this.#browserProcesses.set(wsEndpoint, browser.process());
1270+
response = new Response(wsEndpoint);
12771271
} else if (url.pathname === "/browser/status") {
1278-
const sessionId = url.searchParams.get("sessionId");
1279-
assert(sessionId !== null, "Missing sessionId query parameter");
1280-
const process = this.#browserProcesses.get(sessionId);
1281-
response = new Response(null, { status: process ? 200 : 410 });
1282-
} else if (url.pathname === "/browser/sessionIds") {
1283-
const sessionIds = this.#browserProcesses.keys();
1284-
response = Response.json(Array.from(sessionIds));
1272+
const wsEndpoint = url.searchParams.get("wsEndpoint");
1273+
assert(wsEndpoint !== null, "Missing wsEndpoint query parameter");
1274+
const process = this.#browserProcesses.get(wsEndpoint);
1275+
const status = {
1276+
stopped: !process || process.exitCode !== null,
1277+
};
1278+
response = new Response(JSON.stringify(status), {
1279+
headers: { "Content-Type": "application/json" },
1280+
});
12851281
} else if (url.pathname === "/core/store-temp-file") {
12861282
const prefix = url.searchParams.get("prefix");
12871283
const folder = prefix ? `files/${prefix}` : "files";
@@ -2005,10 +2001,10 @@ export class Miniflare {
20052001
}
20062002

20072003
async #assembleAndUpdateConfig() {
2008-
for (const [sessionId, process] of this.#browserProcesses.entries()) {
2004+
for (const [wsEndpoint, process] of this.#browserProcesses.entries()) {
20092005
// .close() isn't enough
20102006
process.kill("SIGKILL");
2011-
this.#browserProcesses.delete(sessionId);
2007+
this.#browserProcesses.delete(wsEndpoint);
20122008
}
20132009
// This function must be run with `#runtimeMutex` held
20142010
const initial = !this.#runtimeEntryURL;
@@ -2713,10 +2709,10 @@ export class Miniflare {
27132709
try {
27142710
await this.#waitForReady(/* disposing */ true);
27152711
} finally {
2716-
for (const [sessionId, process] of this.#browserProcesses.entries()) {
2712+
for (const [wsEndpoint, process] of this.#browserProcesses.entries()) {
27172713
// .close() isn't enough
27182714
process.kill("SIGKILL");
2719-
this.#browserProcesses.delete(sessionId);
2715+
this.#browserProcesses.delete(wsEndpoint);
27202716
}
27212717

27222718
// Remove exit hook, we're cleaning up what they would've cleaned up now

packages/miniflare/src/workers/browser-rendering/binding.worker.ts

Lines changed: 26 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,23 @@ function isClosed(ws: WebSocket | undefined): boolean {
1212
return !ws || ws.readyState === WebSocket.CLOSED;
1313
}
1414

15-
export type SessionInfo = {
16-
wsEndpoint: string;
17-
sessionId: string;
18-
startTime: number;
19-
connectionId?: string;
20-
connectionStartTime?: number;
21-
};
22-
2315
export class BrowserSession extends DurableObject<Env> {
24-
sessionInfo?: SessionInfo;
16+
endpoint?: string;
2517
ws?: WebSocket;
2618
server?: WebSocket;
2719

2820
async fetch(_request: Request) {
2921
assert(
30-
this.sessionInfo !== undefined,
31-
"sessionInfo must be set before connecting"
22+
this.endpoint !== undefined,
23+
"endpoint must be set before connecting"
3224
);
3325

3426
// sometimes the websocket doesn't get the close event, so we need to close them explicitly if needed
3527
if (isClosed(this.ws) || isClosed(this.server)) {
36-
this.closeWebSockets();
28+
this.ws?.close();
29+
this.server?.close();
30+
this.ws = undefined;
31+
this.server = undefined;
3732
} else {
3833
assert.fail("WebSocket already initialized");
3934
}
@@ -43,7 +38,7 @@ export class BrowserSession extends DurableObject<Env> {
4338

4439
server.accept();
4540

46-
const wsEndpoint = this.sessionInfo.wsEndpoint.replace("ws://", "http://");
41+
const wsEndpoint = this.endpoint.replace("ws://", "http://");
4742

4843
const response = await fetch(wsEndpoint, {
4944
headers: {
@@ -90,51 +85,37 @@ export class BrowserSession extends DurableObject<Env> {
9085
});
9186
this.ws = ws;
9287
this.server = server;
93-
this.sessionInfo.connectionId = crypto.randomUUID();
94-
this.sessionInfo.connectionStartTime = Date.now();
9588

9689
return new Response(null, {
9790
status: 101,
9891
webSocket: client,
9992
});
10093
}
101-
102-
async setSessionInfo(sessionInfo: SessionInfo) {
103-
this.sessionInfo = sessionInfo;
104-
}
105-
106-
async getSessionInfo(): Promise<SessionInfo | undefined> {
107-
if (isClosed(this.ws) || isClosed(this.server)) {
108-
this.closeWebSockets();
109-
}
110-
return this.sessionInfo;
94+
async setEndpoint(endpoint: string) {
95+
this.endpoint = endpoint;
11196
}
11297

11398
async #checkStatus() {
114-
if (this.sessionInfo) {
99+
if (this.endpoint) {
115100
const url = new URL("http://example.com/browser/status");
116-
url.searchParams.set("sessionId", this.sessionInfo.sessionId);
101+
url.searchParams.set("wsEndpoint", this.endpoint);
117102
const resp = await this.env[CoreBindings.SERVICE_LOOPBACK].fetch(url);
103+
const { stopped } = resp.ok
104+
? ((await resp.json()) as { stopped: boolean })
105+
: {};
118106

119-
if (!resp.ok) {
107+
if (stopped) {
120108
// Browser process has exited, we should close the WebSocket
121109
// TODO should we send a error code?
122-
this.closeWebSockets();
110+
this.ws?.close();
111+
this.server?.close();
112+
this.ws = undefined;
113+
this.server = undefined;
114+
this.ctx.storage.deleteAll();
123115
return;
124116
}
125117
}
126118
}
127-
128-
closeWebSockets() {
129-
this.ws?.close();
130-
this.server?.close();
131-
this.ws = undefined;
132-
this.server = undefined;
133-
if (this.sessionInfo) {
134-
this.sessionInfo.connectionId = undefined;
135-
this.sessionInfo.connectionStartTime = undefined;
136-
}
137-
}
138119
}
139120

140121
export default {
@@ -145,39 +126,18 @@ export default {
145126
const resp = await env[CoreBindings.SERVICE_LOOPBACK].fetch(
146127
"http://example.com/browser/launch"
147128
);
148-
const sessionInfo: SessionInfo = await resp.json();
149-
const id = env.BrowserSession.idFromName(sessionInfo.sessionId);
150-
await env.BrowserSession.get(id).setSessionInfo(sessionInfo);
151-
return Response.json({ sessionId: sessionInfo.sessionId });
129+
const wsEndpoint = await resp.text();
130+
const sessionId = crypto.randomUUID();
131+
const id = env.BrowserSession.idFromName(sessionId);
132+
await env.BrowserSession.get(id).setEndpoint(wsEndpoint);
133+
return Response.json({ sessionId });
152134
}
153135
case "/v1/connectDevtools": {
154136
const sessionId = url.searchParams.get("browser_session");
155137
assert(sessionId !== null, "browser_session must be set");
156138
const id = env.BrowserSession.idFromName(sessionId);
157139
return env.BrowserSession.get(id).fetch(request);
158140
}
159-
case "/v1/sessions": {
160-
const sessionIds = (await env[CoreBindings.SERVICE_LOOPBACK]
161-
.fetch("http://example.com/browser/sessionIds")
162-
.then((resp) => resp.json())) as string[];
163-
const sessions = await Promise.all(
164-
sessionIds.map(async (sessionId) => {
165-
const id = env.BrowserSession.idFromName(sessionId);
166-
return env.BrowserSession.get(id)
167-
.getSessionInfo()
168-
.then((sessionInfo) => {
169-
if (!sessionInfo) return null;
170-
return {
171-
sessionId: sessionInfo.sessionId,
172-
startTime: sessionInfo.startTime,
173-
connectionId: sessionInfo.connectionId,
174-
connectionStartTime: sessionInfo.connectionStartTime,
175-
};
176-
});
177-
})
178-
).then((results) => results.filter(Boolean));
179-
return Response.json({ sessions });
180-
}
181141
default:
182142
return new Response("Not implemented", { status: 405 });
183143
}

0 commit comments

Comments
 (0)