gpt4 book ai didi

docker - 调用 puppeteer.connect() 时出现协议(protocol)错误

转载 作者:行者123 更新时间:2023-12-05 04:23:40 24 4
gpt4 key购买 nike

我正在使用 in this post 中列出的基本方法从客户端 docker 容器连接到多个 chrome docker 容器中的任何一个(在 docker 群/服务中,可能跨越 nginx 后面的多个服务器,使用 CapRover 部署)。

在每个 chrome 容器中,我维护一个 browser 对象的池(只是一个简单的数组),并将传入的请求定向到适当的 browser 如下(非常类似于链接的帖子):

import http from 'node:http';       // https://nodejs.org/api/http.html
import httpProxy from 'http-proxy'; // https://www.npmjs.com/package/http-proxy

const proxy = new httpProxy.createProxyServer({ ws: true });

// an array (pool) of pre-launched and managed browser objects...
const browsers = [ ... ];

http
.createServer()
.on('upgrade', (req, socket, head) => {
const browser = browsers[Math.floor(Math.random() * browsers.length)]; // in reality I don't just pick a browser at random
const target = browser.wsEndpoint();
proxy.ws(req, socket, head, { target });
})
.listen(3222);

以上是在 ws://srv-captain--chrome:3222 上监听(通信是通过容器之间的 docker 网络进行的“内部”通信)。

然后,在我的客户端容器中,我连接到公共(public)端点 ws://srv-captain--chrome:3222,如下所示:

import puppeteer from 'puppeteer'; // https://www.npmjs.com/package/puppeteer (using version 17.1.3 at time of posting this)
try {
const browser = await puppeteer.connect({ browserWSEndpoint: 'ws://srv-captain--chrome:3222' });
} catch (err) {
console.error('error connecting to browser', err);
}

这真的很好用,只是在上面的客户端容器中调用 puppeteer.connect() 时,我遇到了类似这样的偶尔/不一致错误:

Protocol error (Emulation.setDeviceMetricsOverride): Session closed. Most likely the page has been closed.
Protocol error (Performance.enable): Target closed.

几乎总是,如果我只是简单地再次尝试连接,连接就会在没有进一步错误的情况下建立,而且是在第一次尝试时。

我不知道为什么错误是提示页面已关闭目标已关闭,因为在这个过程中,我没有尝试与任何 页面 交互,我从监听 browser.on('disconnected'...) 以及监控 chromium 进程本身得知,每个 数组中的浏览器仍然工作正常......没有崩溃。

知道这里发生了什么吗?


进一步测试后更新

当然,在客户端容器中,我们连接到浏览器并不是像上面的片段那样,而是为了打开一个页面并使用 页面 做一些事情。实际上,在客户端容器中它更像是下面的测试片段:

const doIteration = function (i) {
return new Promise(async (resolve, reject) => {
// mimic incoming requests coming in at random times over a short period by introducing a random initial delay...
await new Promise(resolve => setTimeout(resolve, Math.random() * 5000));
// now actually connect...
let browser;
try {
browser = await puppeteer.connect({ browserWSEndpoint: `ws://srv-captain--chrome:3222?queryParam=loop_${i}` });
} catch (err) {
reject(err);
return;
}
// now that we have a browser, open a new page...
const page = await browser.newPage();
// do something useful with the page (not shown here) and then close it..
await page.close();
// now disconnect (but don't close) the browser...
browser.disconnect();
resolve();
});
};

const promises = [];
for (let i = 0; i < 15; i++) {
promises.push( doIteration(i) );
}

try {
await Promise.all(promises);
} catch (err) {
console.error(`error doing stuff`, err);
}

上面的每个迭代都同时执行了多次...我在迭代数组上使用 Promise.all() promise 在我的生产代码中模拟多个并发传入请求。以上足以重现问题...错误不会发生在调用 puppeteer.connect()every 迭代,只是一些。

所以在一次迭代中打开/关闭一个页面和在另一次迭代中调用puppeteer.connect()之间似乎存在某种相互作用,尽管关闭了页面并在每次迭代中正确断开浏览器?这可能也解释了在调用 puppeteer.connect() 时如果有一些与 page 相关的宿醉,则 Most likely the page has been closed 错误消息> 在另一次迭代中关闭...尽管由于某种原因,调用 puppeteer.connect() 时会出现此错误?


通过使用 browsers 数组中的 browser 对象池,以及在多个服务器上具有多个容器的 docker swarm,每个升级 消息可以在不同的容器(甚至可以在不同的服务器上)接收,并且可以路由到 browsers 数组中的不同的 browser。但我现在认为这是一个转移注意力的问题,因为在进一步的测试中,我通过将所有请求路由到 browsers[0] 并将服务缩小到一个容器来缩小问题范围......因此 upgrade 消息始终由同一服务器上的同一容器处理并路由到同一 browser... 问题仍然存在。


上述错误的完整堆栈跟踪:

Error: Protocol error (Emulation.setDeviceMetricsOverride): Session closed. Most likely the page has been closed.
at CDPSession.send (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Connection.js:281:35)
at EmulationManager.emulateViewport (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/EmulationManager.js:33:73)
at Page.setViewport (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Page.js:1776:93)
at Function._create (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Page.js:242:24)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Target.page (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Target.js:123:23)
at async Promise.all (index 0)
at async BrowserContext.pages (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Browser.js:577:23)
at async Promise.all (index 0)

最佳答案

随着我越来越深入地研究这个问题,越来越明显的是我实际上可能没有做任何根本性的错误,这可能只是 puppeteer 本身的一个错误。所以我将这些报告为 an issue over on puppeteer ...事实上,它被认为是 15.5.0 之后的任何版本的错误,并且正在修复。与此同时,解决方法是恢复到 puppeteer 版本 15.5.0 并在使用并发连接时调用 browser.pages() 时要小心,因为这可能本身会抛出错误...但我知道这也可能是他们可以/将会修复的问题,以便 browser.pages() 对并发连接的存在更有弹性。

关于docker - 调用 puppeteer.connect() 时出现协议(protocol)错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73670998/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com