cron 스케줄러 한국 시간대 적용 및 봇 카드 UI 개선
- scheduler.js: cron.schedule에 timezone: 'Asia/Seoul' 옵션 추가 - bots.js: Meilisearch 봇 API에 버전 정보 추가 - BotCard.jsx: Meilisearch 봇 카드에 마지막 동기화 시간, 동기화 수, 버전 표시 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8091f4ac67
commit
95285634e9
3 changed files with 37 additions and 14 deletions
|
|
@ -4,6 +4,7 @@ import bots from '../config/bots.js';
|
||||||
import { syncWithRetry, getVersion } from '../services/meilisearch/index.js';
|
import { syncWithRetry, getVersion } from '../services/meilisearch/index.js';
|
||||||
|
|
||||||
const REDIS_PREFIX = 'bot:status:';
|
const REDIS_PREFIX = 'bot:status:';
|
||||||
|
const TIMEZONE = 'Asia/Seoul';
|
||||||
|
|
||||||
async function schedulerPlugin(fastify, opts) {
|
async function schedulerPlugin(fastify, opts) {
|
||||||
const tasks = new Map();
|
const tasks = new Map();
|
||||||
|
|
@ -60,7 +61,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
const CHECK_INTERVAL = 60 * 1000; // 1분
|
const CHECK_INTERVAL = 60 * 1000; // 1분
|
||||||
const CHECK_DURATION = 5 * 60 * 1000; // 5분간 체크
|
const CHECK_DURATION = 5 * 60 * 1000; // 5분간 체크
|
||||||
|
|
||||||
// 체크 시작 cron (매일 4시)
|
// 체크 시작 cron (매일 4시 KST)
|
||||||
const task = cron.schedule(bot.cron, async () => {
|
const task = cron.schedule(bot.cron, async () => {
|
||||||
fastify.log.info(`[${botId}] 버전 체크 시작 (5분간 1분 간격)`);
|
fastify.log.info(`[${botId}] 버전 체크 시작 (5분간 1분 간격)`);
|
||||||
await updateStatus(botId, { status: 'running' });
|
await updateStatus(botId, { status: 'running' });
|
||||||
|
|
@ -114,7 +115,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
await performSync(botId, currentVersion, REDIS_VERSION_KEY);
|
await performSync(botId, currentVersion, REDIS_VERSION_KEY);
|
||||||
}
|
}
|
||||||
}, CHECK_INTERVAL);
|
}, CHECK_INTERVAL);
|
||||||
});
|
}, { timezone: TIMEZONE });
|
||||||
|
|
||||||
tasks.set(botId, task);
|
tasks.set(botId, task);
|
||||||
await updateStatus(botId, { status: 'running' });
|
await updateStatus(botId, { status: 'running' });
|
||||||
|
|
@ -202,7 +203,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
throw new Error(`지원하지 않는 봇 타입: ${bot.type}`);
|
throw new Error(`지원하지 않는 봇 타입: ${bot.type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cron 태스크 등록
|
// cron 태스크 등록 (한국 시간 기준)
|
||||||
const task = cron.schedule(bot.cron, async () => {
|
const task = cron.schedule(bot.cron, async () => {
|
||||||
fastify.log.info(`[${botId}] 동기화 시작`);
|
fastify.log.info(`[${botId}] 동기화 시작`);
|
||||||
try {
|
try {
|
||||||
|
|
@ -217,7 +218,7 @@ async function schedulerPlugin(fastify, opts) {
|
||||||
});
|
});
|
||||||
fastify.log.error(`[${botId}] 동기화 오류: ${err.message}`);
|
fastify.log.error(`[${botId}] 동기화 오류: ${err.message}`);
|
||||||
}
|
}
|
||||||
});
|
}, { timezone: TIMEZONE });
|
||||||
|
|
||||||
tasks.set(botId, task);
|
tasks.set(botId, task);
|
||||||
await updateStatus(botId, { status: 'running' });
|
await updateStatus(botId, { status: 'running' });
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ export default async function botsRoutes(fastify) {
|
||||||
checkInterval = parseInt(cronMatch[1]);
|
checkInterval = parseInt(cronMatch[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({
|
const botData = {
|
||||||
id: bot.id,
|
id: bot.id,
|
||||||
name: bot.name || bot.channelName || bot.username || bot.id,
|
name: bot.name || bot.channelName || bot.username || bot.id,
|
||||||
type: bot.type,
|
type: bot.type,
|
||||||
|
|
@ -78,7 +78,15 @@ export default async function botsRoutes(fastify) {
|
||||||
check_interval: checkInterval,
|
check_interval: checkInterval,
|
||||||
error_message: status.errorMessage,
|
error_message: status.errorMessage,
|
||||||
enabled: bot.enabled,
|
enabled: bot.enabled,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// Meilisearch 봇인 경우 버전 정보 추가
|
||||||
|
if (bot.type === 'meilisearch') {
|
||||||
|
const version = await redis.get('meilisearch:version');
|
||||||
|
botData.version = version || '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(botData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -145,14 +145,28 @@ const BotCard = memo(function BotCard({
|
||||||
{bot.type === 'meilisearch' ? (
|
{bot.type === 'meilisearch' ? (
|
||||||
<>
|
<>
|
||||||
<div className="p-3 text-center">
|
<div className="p-3 text-center">
|
||||||
<div className="text-lg font-bold text-gray-900">{bot.schedules_added || 0}</div>
|
<div className="text-lg font-bold text-gray-900">
|
||||||
<div className="text-xs text-gray-400">동기화 수</div>
|
{bot.last_check_at
|
||||||
|
? new Date(bot.last_check_at).toLocaleString('ko-KR', {
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
})
|
||||||
|
: '-'}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-gray-400">마지막 동기화</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 text-center">
|
<div className="p-3 text-center">
|
||||||
<div className="text-lg font-bold text-gray-900">
|
<div className="text-lg font-bold text-gray-900">
|
||||||
{bot.last_added_count ? `${(bot.last_added_count / 1000 || 0).toFixed(1)}초` : '-'}
|
{bot.last_added_count?.toLocaleString() || '-'}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-400">소요 시간</div>
|
<div className="text-xs text-gray-400">동기화 수</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 text-center">
|
||||||
|
<div className="text-lg font-bold text-gray-900">{bot.version || '-'}</div>
|
||||||
|
<div className="text-xs text-gray-400">버전</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -169,12 +183,12 @@ const BotCard = memo(function BotCard({
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-400">마지막</div>
|
<div className="text-xs text-gray-400">마지막</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div className="p-3 text-center">
|
<div className="p-3 text-center">
|
||||||
<div className="text-lg font-bold text-gray-900">{formatInterval(bot.check_interval)}</div>
|
<div className="text-lg font-bold text-gray-900">{formatInterval(bot.check_interval)}</div>
|
||||||
<div className="text-xs text-gray-400">업데이트 간격</div>
|
<div className="text-xs text-gray-400">업데이트 간격</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 오류 메시지 */}
|
{/* 오류 메시지 */}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue