Files
playwright-gitcode/utils/taskRunner.js
2026-07-06 09:34:39 +08:00

101 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 统一任务执行器
*
* 功能:
* - try/catch 包裹每个任务
* - 自动记录开始/结束/失败日志
* - 单任务失败不影响其他任务
*/
const logger = require('./logger');
const config = require('../config');
const { safeGoto } = require('./page');
function withTimeout(promise, timeoutMs, taskName) {
let timer = null;
const timeout = new Promise((_, reject) => {
timer = setTimeout(() => {
reject(new Error(`${taskName} 单任务超时 ${timeoutMs}ms`));
}, timeoutMs);
});
return Promise.race([promise, timeout]).finally(() => {
if (timer) clearTimeout(timer);
});
}
async function prepareRetry(page, taskName, attempt) {
logger.info(`${taskName} 准备第${attempt}次重试,回到积分中心...`);
await safeGoto(page, config.urls.points, {
label: '积分中心',
timeout: config.navigationTimeout,
waitFor: ['.g-user-avatar', '.novice-task-item-box'],
}).catch((err) => {
logger.warn(` → 重试前刷新积分中心失败: ${err.message}`);
});
await page.waitForTimeout(1000).catch(() => {});
}
/**
* 执行任务(带防护)
*
* @param {string} taskName - 任务显示名称(如 "每日Star"
* @param {Function} handler - 异步任务函数 async (page) => { ... }
* @param {import('playwright').Page} page - 当前页面
* @returns {Promise<boolean>} 任务是否成功
*/
async function runTask(taskName, handler, page) {
logger.divider();
logger.info(`开始执行任务: ${taskName}`);
const maxAttempts = Math.max(1, Number(config.retryCount) || 1);
let lastError = null;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
if (attempt > 1) {
await prepareRetry(page, taskName, attempt);
}
try {
logger.info(`${taskName}${attempt}/${maxAttempts}次尝试`);
await withTimeout(handler(page), config.taskTimeout, taskName);
logger.info(`${taskName} 执行成功`);
return true;
} catch (err) {
lastError = err;
if (attempt < maxAttempts) {
logger.warn(`⚠️ ${taskName}${attempt}/${maxAttempts}次失败: ${err.message}`);
} else {
logger.error(`${taskName} 执行失败: ${err.message}`);
}
}
}
if (lastError && lastError.stack) {
logger.warn(lastError.stack);
}
return false;
}
/**
* 批量执行任务列表
*
* @param {import('playwright').Page} page - 主页面
* @param {Array<{name: string, handler: Function}>} tasks - 任务列表
* @returns {Promise<Object<string, boolean>>} 任务名 → 是否成功
*/
async function runTasks(page, tasks) {
const results = {};
for (const { name, handler } of tasks) {
results[name] = await runTask(name, handler, page);
}
return results;
}
module.exports = {
runTask,
runTasks,
};