fix(scheduler): 봇 JSON 컬럼 파싱에 safeParse 가드 추가
깨진 JSON 값 하나가 getAllBots 전체를 throw시켜 startAll(전체 봇 기동)을 막던 위험 제거. weekly_schedule_config/title_filters/default_member_ids/ auto_schedule_config/text_filters를 safeParse(fallback)로 처리. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
e16d3f1230
commit
6e559a52b7
1 changed files with 18 additions and 25 deletions
|
|
@ -20,6 +20,19 @@ function isActiveMonth(bot) {
|
||||||
return months.includes(monthKST());
|
return months.includes(monthKST());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB JSON 컬럼 안전 파싱. 깨진 값 하나가 getAllBots 전체를 막지 않도록 fallback 반환.
|
||||||
|
*/
|
||||||
|
function safeParse(value, fallback = null) {
|
||||||
|
if (value == null) return fallback;
|
||||||
|
if (typeof value !== 'string') return value;
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 에러 객체에서 활동 로그용 details 구성
|
* 에러 객체에서 활동 로그용 details 구성
|
||||||
* - err.cause(Node fetch failed의 진짜 원인 등), err.code를 함께 포함
|
* - err.cause(Node fetch failed의 진짜 원인 등), err.code를 함께 포함
|
||||||
|
|
@ -47,11 +60,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
'SELECT * FROM bot_youtube'
|
'SELECT * FROM bot_youtube'
|
||||||
);
|
);
|
||||||
return rows.map(row => {
|
return rows.map(row => {
|
||||||
const weekly = row.weekly_schedule_config
|
const weekly = safeParse(row.weekly_schedule_config, null);
|
||||||
? (typeof row.weekly_schedule_config === 'string'
|
|
||||||
? JSON.parse(row.weekly_schedule_config)
|
|
||||||
: row.weekly_schedule_config)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// weekly 모드면 시작 시각에만 트리거, 아니면 cron_interval 분 주기
|
// weekly 모드면 시작 시각에만 트리거, 아니면 cron_interval 분 주기
|
||||||
let cronExpr;
|
let cronExpr;
|
||||||
|
|
@ -72,23 +81,11 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
bannerUrl: row.banner_url,
|
bannerUrl: row.banner_url,
|
||||||
cron: cronExpr,
|
cron: cronExpr,
|
||||||
enabled: row.enabled === 1,
|
enabled: row.enabled === 1,
|
||||||
titleFilters: row.title_filters
|
titleFilters: safeParse(row.title_filters, []),
|
||||||
? (typeof row.title_filters === 'string'
|
defaultMemberIds: safeParse(row.default_member_ids, []),
|
||||||
? JSON.parse(row.title_filters)
|
|
||||||
: row.title_filters)
|
|
||||||
: [],
|
|
||||||
defaultMemberIds: row.default_member_ids
|
|
||||||
? (typeof row.default_member_ids === 'string'
|
|
||||||
? JSON.parse(row.default_member_ids)
|
|
||||||
: row.default_member_ids)
|
|
||||||
: [],
|
|
||||||
extractMembersFromDesc: row.extract_members_from_desc === 1,
|
extractMembersFromDesc: row.extract_members_from_desc === 1,
|
||||||
extractMembersFromTitle: row.extract_members_from_title === 1,
|
extractMembersFromTitle: row.extract_members_from_title === 1,
|
||||||
autoScheduleNext: row.auto_schedule_config
|
autoScheduleNext: safeParse(row.auto_schedule_config, null),
|
||||||
? (typeof row.auto_schedule_config === 'string'
|
|
||||||
? JSON.parse(row.auto_schedule_config)
|
|
||||||
: row.auto_schedule_config)
|
|
||||||
: null,
|
|
||||||
weeklySchedule: weekly,
|
weeklySchedule: weekly,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
@ -111,11 +108,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
nitterUrl: process.env.NITTER_URL || 'http://nitter:8080',
|
nitterUrl: process.env.NITTER_URL || 'http://nitter:8080',
|
||||||
cron: `*/${row.cron_interval} * * * *`,
|
cron: `*/${row.cron_interval} * * * *`,
|
||||||
enabled: row.enabled === 1,
|
enabled: row.enabled === 1,
|
||||||
textFilters: row.text_filters
|
textFilters: safeParse(row.text_filters, []),
|
||||||
? (typeof row.text_filters === 'string'
|
|
||||||
? JSON.parse(row.text_filters)
|
|
||||||
: row.text_filters)
|
|
||||||
: [],
|
|
||||||
includeRetweets: row.include_retweets === 1,
|
includeRetweets: row.include_retweets === 1,
|
||||||
extractYoutube: row.extract_youtube === 1,
|
extractYoutube: row.extract_youtube === 1,
|
||||||
excludeManagedChannels: row.exclude_managed_channels === 1,
|
excludeManagedChannels: row.exclude_managed_channels === 1,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue