diff options
Diffstat (limited to 'lib/knox-sync/title-sync-service.ts')
| -rw-r--r-- | lib/knox-sync/title-sync-service.ts | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/lib/knox-sync/title-sync-service.ts b/lib/knox-sync/title-sync-service.ts index e7bc13bd..5a8ce42a 100644 --- a/lib/knox-sync/title-sync-service.ts +++ b/lib/knox-sync/title-sync-service.ts @@ -4,17 +4,23 @@ 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 { sql } from 'drizzle-orm'; - -const COMPANIES = (process.env.KNOX_COMPANY_CODES || 'P2') - .split(',') - .map((c) => c.trim()) - .filter(Boolean); +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 upsertTitles(titles: Title[]) { +async function insertTitles(titles: Title[]) { if (!titles.length) return; const rows = titles.map((t) => ({ @@ -26,39 +32,66 @@ async function upsertTitles(titles: Title[]) { raw: t as unknown as Record<string, unknown>, })); - await db - .insert(titleTable) - .values(rows) - .onConflictDoUpdate({ - target: [titleTable.companyCode, titleTable.titleCode], - set: { - titleName: sql.raw('excluded.title_name'), - enTitleName: sql.raw('excluded.en_title_name'), - sortOrder: sql.raw('excluded.sort_order'), - raw: sql.raw('excluded.raw'), - updatedAt: sql.raw('CURRENT_TIMESTAMP'), - }, - }); + await db.insert(titleTable).values(rows); +} + +/** + * 회사별 기존 직급 데이터 삭제 + */ +async function deleteExistingTitles(companyCode: string): Promise<number> { + 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<void> { - console.log('[KNOX-SYNC] 직급 동기화 시작'); + logSyncStart('직급'); + initializeApiTracker(); // API 추적기 초기화 + + let totalApiCalls = 0; + const startTime = Date.now(); + let currentDelay = API_CALL_DELAY_MS; - for (const companyCode of COMPANIES) { + 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); - await upsertTitles(titles); - console.log(`[KNOX-SYNC] 직급 동기화 완료 - ${companyCode}: ${titles.length}건`); + + // 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] 직급 동기화 오류 (company ${companyCode})`, err); + console.error(`[KNOX-SYNC] ${companyCode}: 직급 동기화 오류`, err); } } - console.log('[KNOX-SYNC] 직급 동기화 전체 완료'); + logSyncComplete('직급', totalApiCalls, startTime); } export async function startKnoxTitleSyncScheduler() { if (DO_FIRST_RUN) { + if (!checkTimeRestriction()) { + return; + } + syncKnoxTitles().catch(console.error); } @@ -66,5 +99,5 @@ export async function startKnoxTitleSyncScheduler() { syncKnoxTitles().catch(console.error); }); - console.log(`[KNOX-SYNC] 직급 동기화 스케줄러 등록 (${CRON_STRING})`); + logSchedulerInfo('직급', CRON_STRING); }
\ No newline at end of file |
