diff --git a/backend/src/config/bots.js b/backend/src/config/bots.js index 48445e9..a99d3d6 100644 --- a/backend/src/config/bots.js +++ b/backend/src/config/bots.js @@ -3,7 +3,7 @@ export default [ id: 'meilisearch-sync', type: 'meilisearch', name: 'Meilisearch 동기화', - cron: '0 4 * * *', // 4시부터 5분간 버전 체크, 변경 시 동기화 + cron: '0 12 * * *', // 매일 12시 전체 동기화 enabled: true, }, { diff --git a/backend/src/plugins/scheduler.js b/backend/src/plugins/scheduler.js index f7ed742..0de1257 100644 --- a/backend/src/plugins/scheduler.js +++ b/backend/src/plugins/scheduler.js @@ -1,7 +1,7 @@ import fp from 'fastify-plugin'; import cron from 'node-cron'; import bots from '../config/bots.js'; -import { syncWithRetry, getVersion } from '../services/meilisearch/index.js'; +import { syncAllSchedules } from '../services/meilisearch/index.js'; import { nowKST } from '../utils/date.js'; const REDIS_PREFIX = 'bot:status:'; @@ -48,121 +48,13 @@ async function schedulerPlugin(fastify, opts) { return fastify.xBot.syncNewTweets; } else if (bot.type === 'meilisearch') { return async () => { - const count = await syncWithRetry(fastify.meilisearch, fastify.db); + const count = await syncAllSchedules(fastify.meilisearch, fastify.db); return { addedCount: count, total: count }; }; } return null; } - /** - * Meilisearch 버전 체크 및 동기화 (업데이트 감지용) - */ - async function startMeilisearchVersionCheck(botId, bot) { - const REDIS_VERSION_KEY = 'meilisearch:version'; - const CHECK_INTERVAL = 60 * 1000; // 1분 - const CHECK_DURATION = 5 * 60 * 1000; // 5분간 체크 - - // 체크 시작 cron (매일 4시 KST) - const task = cron.schedule(bot.cron, async () => { - fastify.log.info(`[${botId}] 버전 체크 시작 (5분간 1분 간격)`); - await updateStatus(botId, { status: 'running' }); - - const startTime = Date.now(); - let synced = false; - let checkCount = 0; - - // 초기 버전 저장 - const initialVersion = await getVersion(fastify.meilisearch); - if (!initialVersion) { - fastify.log.error(`[${botId}] Meilisearch 연결 실패`); - await updateStatus(botId, { status: 'error', errorMessage: 'Meilisearch 연결 실패' }); - return; - } - - const savedVersion = await fastify.redis.get(REDIS_VERSION_KEY); - fastify.log.info(`[${botId}] 현재 버전: ${initialVersion}, 저장된 버전: ${savedVersion || '없음'}`); - - // 버전이 이미 다르면 즉시 동기화 - if (savedVersion && savedVersion !== initialVersion) { - fastify.log.info(`[${botId}] 버전 변경 감지! ${savedVersion} → ${initialVersion}`); - await performSync(botId, initialVersion, REDIS_VERSION_KEY); - return; - } - - // 5분간 1분 간격으로 체크 - const intervalId = setInterval(async () => { - checkCount++; - const elapsed = Date.now() - startTime; - - if (synced || elapsed >= CHECK_DURATION) { - clearInterval(intervalId); - if (!synced) { - fastify.log.info(`[${botId}] 버전 변경 없음, 체크 종료`); - await updateStatus(botId, { - status: 'running', - lastCheckAt: nowKST(), - }); - } - return; - } - - const currentVersion = await getVersion(fastify.meilisearch); - fastify.log.info(`[${botId}] 체크 #${checkCount}: 버전 ${currentVersion}`); - - if (currentVersion && currentVersion !== initialVersion) { - synced = true; - clearInterval(intervalId); - fastify.log.info(`[${botId}] 버전 변경 감지! ${initialVersion} → ${currentVersion}`); - await performSync(botId, currentVersion, REDIS_VERSION_KEY); - } - }, CHECK_INTERVAL); - }, { timezone: TIMEZONE }); - - tasks.set(botId, task); - await updateStatus(botId, { status: 'running' }); - fastify.log.info(`[${botId}] 버전 체크 스케줄 시작 (cron: ${bot.cron})`); - - // 초기 버전 저장 (최초 실행 시) - const currentVersion = await getVersion(fastify.meilisearch); - if (currentVersion) { - const savedVersion = await fastify.redis.get(REDIS_VERSION_KEY); - if (!savedVersion) { - await fastify.redis.set(REDIS_VERSION_KEY, currentVersion); - fastify.log.info(`[${botId}] 초기 버전 저장: ${currentVersion}`); - } - } - } - - /** - * 동기화 실행 및 상태 업데이트 - */ - async function performSync(botId, newVersion, versionKey) { - const startTime = Date.now(); - try { - const count = await syncWithRetry(fastify.meilisearch, fastify.db); - const duration = Date.now() - startTime; - await fastify.redis.set(versionKey, newVersion); - await updateStatus(botId, { - status: 'running', - lastCheckAt: nowKST(), - lastAddedCount: count, - lastSyncDuration: duration, - errorMessage: null, - }); - fastify.log.info(`[${botId}] 동기화 완료: ${count}개, ${duration}ms, 새 버전: ${newVersion}`); - } catch (err) { - const duration = Date.now() - startTime; - await updateStatus(botId, { - status: 'error', - lastCheckAt: nowKST(), - lastSyncDuration: duration, - errorMessage: err.message, - }); - fastify.log.error(`[${botId}] 동기화 오류: ${err.message}`); - } - } - /** * 동기화 결과 처리 (중복 코드 제거) */ @@ -199,12 +91,6 @@ async function schedulerPlugin(fastify, opts) { tasks.delete(botId); } - // Meilisearch는 버전 체크 방식 사용 - if (bot.type === 'meilisearch') { - await startMeilisearchVersionCheck(botId, bot); - return; - } - const syncFn = getSyncFunction(bot); if (!syncFn) { throw new Error(`지원하지 않는 봇 타입: ${bot.type}`); diff --git a/backend/src/routes/admin/bots.js b/backend/src/routes/admin/bots.js index bc87438..e75980d 100644 --- a/backend/src/routes/admin/bots.js +++ b/backend/src/routes/admin/bots.js @@ -62,14 +62,17 @@ export default async function botsRoutes(fastify) { for (const bot of bots) { const status = await scheduler.getStatus(bot.id); - // cron 표현식에서 간격 추출 (분 단위) + // cron 표현식에서 간격 추출 (분 단위, 일일 스케줄은 1440분) let checkInterval = 2; // 기본값 const cronMatch = bot.cron.match(/^\*\/(\d+)/); if (cronMatch) { checkInterval = parseInt(cronMatch[1]); + } else if (/^0 \d+ \* \* \*$/.test(bot.cron)) { + // 매일 특정 시간 (예: 0 12 * * *) + checkInterval = 1440; // 24시간 = 1440분 } - const botData = { + result.push({ id: bot.id, name: bot.name || bot.channelName || bot.username || bot.id, type: bot.type, @@ -81,15 +84,7 @@ export default async function botsRoutes(fastify) { check_interval: checkInterval, error_message: status.errorMessage, enabled: bot.enabled, - }; - - // Meilisearch 봇인 경우 버전 정보 추가 - if (bot.type === 'meilisearch') { - const version = await redis.get('meilisearch:version'); - botData.version = version || '-'; - } - - result.push(botData); + }); } return result; diff --git a/docker-compose.yml b/docker-compose.yml index cbe6fd1..c797c07 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,8 @@ services: meilisearch: image: getmeili/meilisearch:latest container_name: fromis9-meilisearch + labels: + - "com.centurylinklabs.watchtower.enable=false" environment: - MEILI_MASTER_KEY=${MEILI_MASTER_KEY} volumes: diff --git a/frontend/src/components/pc/admin/bot/BotCard.jsx b/frontend/src/components/pc/admin/bot/BotCard.jsx index 5df1c23..85737b6 100644 --- a/frontend/src/components/pc/admin/bot/BotCard.jsx +++ b/frontend/src/components/pc/admin/bot/BotCard.jsx @@ -142,47 +142,22 @@ const BotCard = memo(function BotCard({ {/* 통계 정보 */}