fix(bot): 동시성 중복 INSERT 시 ER_DUP_ENTRY 에러 무시 처리

YouTube/X 봇의 영상 저장 트랜잭션에서 UNIQUE 제약 위반 발생 시
크래시 대신 null을 반환하여 gracefully 무시하도록 변경.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-02-23 15:28:27 +09:00
parent 3feb23f67f
commit f8acb5450f
2 changed files with 59 additions and 46 deletions

View file

@ -103,7 +103,8 @@ async function xBotPlugin(fastify, opts) {
} }
// 트랜잭션으로 INSERT 작업 수행 // 트랜잭션으로 INSERT 작업 수행
return withTransaction(fastify.db, async (connection) => { try {
return await withTransaction(fastify.db, async (connection) => {
// schedules 테이블에 저장 // schedules 테이블에 저장
const [result] = await connection.query( const [result] = await connection.query(
'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)', 'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)',
@ -119,6 +120,11 @@ async function xBotPlugin(fastify, opts) {
return scheduleId; return scheduleId;
}); });
} catch (err) {
// UNIQUE 제약 위반 (동시성 중복) → 무시
if (err.code === 'ER_DUP_ENTRY') return null;
throw err;
}
} }
/** /**

View file

@ -276,7 +276,9 @@ async function youtubeBotPlugin(fastify) {
} }
// 트랜잭션으로 INSERT 작업 수행 // 트랜잭션으로 INSERT 작업 수행
const scheduleId = await withTransaction(fastify.db, async (connection) => { let scheduleId;
try {
scheduleId = await withTransaction(fastify.db, async (connection) => {
// schedules 테이블에 저장 // schedules 테이블에 저장
const [result] = await connection.query( const [result] = await connection.query(
'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)', 'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)',
@ -312,6 +314,11 @@ async function youtubeBotPlugin(fastify) {
return newScheduleId; return newScheduleId;
}); });
} catch (err) {
// UNIQUE 제약 위반 (동시성 중복) → 무시
if (err.code === 'ER_DUP_ENTRY') return null;
throw err;
}
// 새 영상 추가 후 다음 주 예정 일정 생성 (쇼츠 제외) // 새 영상 추가 후 다음 주 예정 일정 생성 (쇼츠 제외)
if (autoScheduleNext && isVideoType && scheduleId) { if (autoScheduleNext && isVideoType && scheduleId) {