From 2ddf2ec749fc3b0001b5d140033736d1c4fe68dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Thu, 8 Jan 2026 16:29:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BD=91=E7=BB=9C=E8=AF=B7=E6=B1=82):=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B6=85=E6=97=B6=E5=92=8C=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=E6=8F=90=E5=8D=87=E7=A8=B3=E5=AE=9A=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为 asyncHttpsGet 添加超时参数,默认10秒 在 TuneHub 服务中实现3次重试机制,每次增加超时时间 优化错误日志记录,包含更多调试信息 --- backend/src/handler/sync_jobs.js | 2 +- backend/src/service/music_platform/tunehub.js | 45 ++++++++++++++----- backend/src/utils/network.js | 9 +++- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/backend/src/handler/sync_jobs.js b/backend/src/handler/sync_jobs.js index 75e86e5..6c2f530 100644 --- a/backend/src/handler/sync_jobs.js +++ b/backend/src/handler/sync_jobs.js @@ -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 diff --git a/backend/src/service/music_platform/tunehub.js b/backend/src/service/music_platform/tunehub.js index 0f4a565..4ea7d67 100644 --- a/backend/src/service/music_platform/tunehub.js +++ b/backend/src/service/music_platform/tunehub.js @@ -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, { diff --git a/backend/src/utils/network.js b/backend/src/utils/network.js index 481fad6..b94fcfb 100644 --- a/backend/src/utils/network.js +++ b/backend/src/utils/network.js @@ -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); });