'use server'; import * as cron from 'node-cron'; import db from '@/db/db'; import { title as titleTable } from '@/db/schema/knox/titles'; import { getTitlesByCompany, Title } from '@/lib/knox-api/employee/employee'; import { eq } from 'drizzle-orm'; import { KNOX_COMPANIES, delay, API_CALL_DELAY_MS, checkTimeRestriction, checkApiLimitStatus, initializeApiTracker, logSyncStart, logSyncComplete, logSchedulerInfo, } from './common'; const CRON_STRING = process.env.KNOX_TITLE_SYNC_CRON || '30 4 * * *'; const DO_FIRST_RUN = process.env.KNOX_TITLE_SYNC_FIRST_RUN === 'true'; async function insertTitles(titles: Title[]) { if (!titles.length) return; const rows = titles.map((t) => ({ companyCode: t.companyCode, titleCode: t.titleCode, titleName: t.titleName, enTitleName: t.enTitleName, sortOrder: t.sortOrder, raw: t as unknown as Record, })); await db.insert(titleTable).values(rows); } /** * 회사별 기존 직급 데이터 삭제 */ async function deleteExistingTitles(companyCode: string): Promise { const result = await db .delete(titleTable) .where(eq(titleTable.companyCode, companyCode)); const deletedCount = result.rowCount || 0; console.log(`[KNOX-SYNC] ${companyCode}: 기존 직급 데이터 ${deletedCount}건 삭제 완료`); return deletedCount; } export async function syncKnoxTitles(): Promise { logSyncStart('직급'); initializeApiTracker(); // API 추적기 초기화 let totalApiCalls = 0; const startTime = Date.now(); let currentDelay = API_CALL_DELAY_MS; for (const companyCode of KNOX_COMPANIES) { try { console.log(`[KNOX-SYNC] ${companyCode}: 직급 동기화 시작 (Delete-Insert 방식)`); // 1단계: 기존 데이터 삭제 await deleteExistingTitles(companyCode); // 2단계: 회사 간 딜레이 적용 (첫 번째 회사 제외) if (totalApiCalls > 0) { await delay(currentDelay); } // 3단계: 새로운 직급 데이터 조회 및 삽입 const titles = await getTitlesByCompany(companyCode); // API 제한 체크 및 delay 조절 const limitStatus = checkApiLimitStatus(1); currentDelay = limitStatus.recommendedDelay; totalApiCalls++; await insertTitles(titles); console.log(`[KNOX-SYNC] ${companyCode}: 직급 동기화 완료 - ${titles.length}건, API 호출 1회`); } catch (err) { console.error(`[KNOX-SYNC] ${companyCode}: 직급 동기화 오류`, err); } } logSyncComplete('직급', totalApiCalls, startTime); } export async function startKnoxTitleSyncScheduler() { if (DO_FIRST_RUN) { if (!checkTimeRestriction()) { return; } syncKnoxTitles().catch(console.error); } cron.schedule(CRON_STRING, () => { syncKnoxTitles().catch(console.error); }); logSchedulerInfo('직급', CRON_STRING); }