Refactor GitCode daily bot

This commit is contained in:
2026-07-06 09:34:39 +08:00
parent 120ae7d3f9
commit 77a07aae0a
19 changed files with 2251 additions and 533 deletions

100
utils/taskRunner.js Normal file
View File

@@ -0,0 +1,100 @@
/**
* 统一任务执行器
*
* 功能:
* - 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,
};