feat: 新增 debugOpts 支持配置 Puppeteer 信号处理行为,优化 demo 中 Ctrl+C 处理逻辑以保持浏览器可复用
This commit is contained in:
@@ -286,9 +286,19 @@ async function connectBrowser(port) {
|
||||
* @param {number} opts.port
|
||||
* @param {string} opts.userDataDir
|
||||
* @param {boolean} opts.headless
|
||||
* @param {object} [opts.debugOpts] - 调试/信号控制选项
|
||||
* @param {boolean} [opts.debugOpts.handleSIGINT=true] - Puppeteer 是否在 SIGINT 时自动关闭浏览器
|
||||
* @param {boolean} [opts.debugOpts.handleSIGTERM=true] - Puppeteer 是否在 SIGTERM 时自动关闭浏览器
|
||||
* @param {boolean} [opts.debugOpts.handleSIGHUP=true] - Puppeteer 是否在 SIGHUP 时自动关闭浏览器
|
||||
* @returns {Promise<import('puppeteer-core').Browser>}
|
||||
*/
|
||||
async function launchBrowser({ executablePath, port, userDataDir, headless }) {
|
||||
async function launchBrowser({ executablePath, port, userDataDir, headless, debugOpts = {} }) {
|
||||
const {
|
||||
handleSIGINT = true,
|
||||
handleSIGTERM = true,
|
||||
handleSIGHUP = true,
|
||||
} = debugOpts;
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
executablePath,
|
||||
headless,
|
||||
@@ -300,6 +310,9 @@ async function launchBrowser({ executablePath, port, userDataDir, headless }) {
|
||||
],
|
||||
ignoreDefaultArgs: ['--enable-automation'],
|
||||
protocolTimeout: config.browserProtocolTimeout,
|
||||
handleSIGINT,
|
||||
handleSIGTERM,
|
||||
handleSIGHUP,
|
||||
});
|
||||
console.log('[browser] launched, pid:', browser.process()?.pid, 'port:', port, 'path:', executablePath);
|
||||
return browser;
|
||||
@@ -349,6 +362,7 @@ async function findOrCreateGeminiPage(browser) {
|
||||
* @param {number} [opts.port] - 调试端口(env: BROWSER_DEBUG_PORT,默认 9222)
|
||||
* @param {string} [opts.userDataDir] - 用户数据目录(env: BROWSER_USER_DATA_DIR,不传则多级兜底)
|
||||
* @param {boolean} [opts.headless] - 无头模式(env: BROWSER_HEADLESS,默认 false)
|
||||
* @param {object} [opts.debugOpts] - 调试/信号控制选项(透传给 Puppeteer launch)
|
||||
* @returns {Promise<{browser: import('puppeteer-core').Browser, page: import('puppeteer-core').Page}>}
|
||||
*/
|
||||
export async function ensureBrowser(opts = {}) {
|
||||
@@ -357,6 +371,7 @@ export async function ensureBrowser(opts = {}) {
|
||||
port = config.browserDebugPort,
|
||||
userDataDir = resolveUserDataDir(),
|
||||
headless = config.browserHeadless,
|
||||
debugOpts,
|
||||
} = opts;
|
||||
|
||||
// 1. 复用已有连接
|
||||
@@ -393,7 +408,7 @@ export async function ensureBrowser(opts = {}) {
|
||||
}
|
||||
|
||||
try {
|
||||
_browser = await launchBrowser({ executablePath: resolvedPath, port, userDataDir, headless });
|
||||
_browser = await launchBrowser({ executablePath: resolvedPath, port, userDataDir, headless, debugOpts });
|
||||
} catch (err) {
|
||||
// 大概率是用户数据目录被正在运行的浏览器锁住了
|
||||
if (err.message?.includes('EPERM') || err.message?.includes('lock') || err.message?.includes('already')) {
|
||||
|
||||
21
src/demo.js
21
src/demo.js
@@ -50,8 +50,18 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
* 创建会话,如果因浏览器目录被锁而失败,自动杀掉全部浏览器进程后重试一次
|
||||
*/
|
||||
async function createSessionWithRetry() {
|
||||
// 禁止 Puppeteer 在 Ctrl+C 等信号时自动杀浏览器进程,
|
||||
// 由 demo 自己处理 SIGINT → disconnect,浏览器保持运行可复用。
|
||||
const opts = {
|
||||
debugOpts: {
|
||||
handleSIGINT: false,
|
||||
handleSIGTERM: false,
|
||||
handleSIGHUP: false,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
return await createGeminiSession();
|
||||
return await createGeminiSession(opts);
|
||||
} catch (err) {
|
||||
const msg = err.message || '';
|
||||
const isLocked = msg.includes('EPERM') || msg.includes('lock') || msg.includes('already');
|
||||
@@ -67,7 +77,7 @@ async function createSessionWithRetry() {
|
||||
await sleep(2000);
|
||||
|
||||
// 重试一次,还失败就直接抛出
|
||||
return await createGeminiSession();
|
||||
return await createGeminiSession(opts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +87,13 @@ async function main() {
|
||||
// 创建会话:自带杀进程重试逻辑
|
||||
const { ops } = await createSessionWithRetry();
|
||||
|
||||
// ── Ctrl+C 时只断开连接,不杀浏览器进程(下次可复用) ──
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n[demo] Ctrl+C 收到,断开浏览器连接(浏览器保持运行)...');
|
||||
disconnect();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
try {
|
||||
// 1. 探测页面状态
|
||||
console.log('[1] 探测页面元素...');
|
||||
|
||||
@@ -30,6 +30,10 @@ export { disconnect, close };
|
||||
* @param {number} [opts.port] - 调试端口(env: BROWSER_DEBUG_PORT,默认 9222)
|
||||
* @param {string} [opts.userDataDir] - 用户数据目录(env: BROWSER_USER_DATA_DIR)
|
||||
* @param {boolean} [opts.headless] - 无头模式(env: BROWSER_HEADLESS,默认 false)
|
||||
* @param {object} [opts.debugOpts] - 调试/信号控制选项(透传给 Puppeteer launch)
|
||||
* @param {boolean} [opts.debugOpts.handleSIGINT=true] - Puppeteer 是否在 SIGINT 时自动关闭浏览器
|
||||
* @param {boolean} [opts.debugOpts.handleSIGTERM=true] - Puppeteer 是否在 SIGTERM 时自动关闭浏览器
|
||||
* @param {boolean} [opts.debugOpts.handleSIGHUP=true] - Puppeteer 是否在 SIGHUP 时自动关闭浏览器
|
||||
* @returns {Promise<{ops: ReturnType<typeof createOps>, page: import('puppeteer-core').Page, browser: import('puppeteer-core').Browser}>}
|
||||
*/
|
||||
export async function createGeminiSession(opts = {}) {
|
||||
|
||||
Reference in New Issue
Block a user