feat(网络请求): 增加超时和重试机制提升稳定性
为 asyncHttpsGet 添加超时参数,默认10秒 在 TuneHub 服务中实现3次重试机制,每次增加超时时间 优化错误日志记录,包含更多调试信息
This commit is contained in:
@@ -65,7 +65,7 @@ async function createJob(req, res) {
|
||||
}
|
||||
|
||||
let meta = {};
|
||||
const songId = request.urlJob && request.urlJob.meta.songId ? request.urlJob.meta.songId : "";
|
||||
let songId = request.urlJob && request.urlJob.meta.songId ? request.urlJob.meta.songId : "";
|
||||
logger.info(`[createJob] songId=${songId}`);
|
||||
|
||||
// 先从 TuneHub 获取歌曲信息,避免显示原始 URL
|
||||
|
||||
@@ -8,16 +8,21 @@ function buildApiUrl(params = {}) {
|
||||
return `${BaseUrl}?${searchParams.toString()}`;
|
||||
}
|
||||
|
||||
async function fetchJson(params = {}) {
|
||||
async function fetchJson(params = {}, attempt = 1) {
|
||||
const url = buildApiUrl(params);
|
||||
const raw = await asyncHttpsGet(url);
|
||||
// 重试时增加超时时间
|
||||
const timeoutMs = Math.min(30000, 5000 + attempt * 5000);
|
||||
logger.info(`[TuneHub] Fetching: ${url} (attempt ${attempt}, timeout ${timeoutMs}ms)`);
|
||||
const raw = await asyncHttpsGet(url, timeoutMs);
|
||||
if (!raw) {
|
||||
logger.warn(`[TuneHub] No data received for ${url}`);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch (err) {
|
||||
logger.error(`TuneHub 返回非 JSON: ${url}`);
|
||||
logger.error(`[TuneHub] Failed to parse JSON from ${url}: ${err.message}`);
|
||||
logger.error(`[TuneHub] Raw response: ${raw.substring(0, 200)}...`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -35,15 +40,33 @@ async function getPlaylistDetail(source, playlistId) {
|
||||
}
|
||||
|
||||
async function getSongInfo(source, songId) {
|
||||
const response = await fetchJson({
|
||||
source,
|
||||
id: songId,
|
||||
type: 'info',
|
||||
});
|
||||
if (!response || response.code !== 200 || !response.data) {
|
||||
return false;
|
||||
// 增加重试机制,提高成功率
|
||||
const maxRetries = 3;
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
logger.info(`[TuneHub] Attempt ${attempt}/${maxRetries} to get song info: ${source}:${songId}`);
|
||||
const response = await fetchJson({
|
||||
source,
|
||||
id: songId,
|
||||
type: 'info',
|
||||
}, attempt);
|
||||
if (response && response.code === 200 && response.data) {
|
||||
logger.info(`[TuneHub] Success: ${source}:${songId}`);
|
||||
return response.data;
|
||||
}
|
||||
logger.warn(`[TuneHub] Failed attempt ${attempt}: code=${response?.code || 'no response'}, data=${!!response?.data}`);
|
||||
if (attempt < maxRetries) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`[TuneHub] Error on attempt ${attempt}: ${error.message}`);
|
||||
if (attempt < maxRetries) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.data;
|
||||
logger.error(`[TuneHub] All ${maxRetries} attempts failed for ${source}:${songId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
async function searchSongs(keyword, {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const https = require('https');
|
||||
|
||||
function asyncHttpsGet(url) {
|
||||
function asyncHttpsGet(url, timeoutMs = 10000) {
|
||||
return new Promise((resolve) => {
|
||||
const timeout = setTimeout(() => {
|
||||
console.error(`[asyncHttpsGet] Timeout after ${timeoutMs}ms: ${url}`);
|
||||
resolve(null);
|
||||
}, timeoutMs);
|
||||
|
||||
https.get(url, res => {
|
||||
let data = '';
|
||||
|
||||
@@ -10,10 +15,12 @@ function asyncHttpsGet(url) {
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
clearTimeout(timeout);
|
||||
resolve(data.toString());
|
||||
});
|
||||
|
||||
}).on('error', err => {
|
||||
clearTimeout(timeout);
|
||||
console.error(err);
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user