Vercel Cron Jobs 설정
Vercel에서 Cron Jobs를 설정하여 정기적인 작업을 자동화하는 방법을 알아봅니다.
Vercel Cron Jobs 설정
Introduction
Cron Jobs는 정기적으로 실행되는 작업을 자동화하는 데 유용합니다. Vercel에서 Cron Jobs를 설정하고 관리하는 방법을 알아보겠습니다.
Environment
- Vercel 프로젝트 (Next.js 14+)
- Vercel Pro 플랜
- Node.js 18+
- 외부 API 통합
Problem
정기적인 작업을 수동으로 실행해야 하는 문제:
# 매일 아침 데이터베이스 백업
# 매주 리포트 생성
# 매월 사용량 분석
# 수동으로 실행하면 실수할 수 있음Analysis
Vercel Cron Jobs의 특징:
- 무료 플랜 제한: Hobby 플랜은 Cron Jobs 지원 안함
- 최소 1분 간격: 1분 미만 간격은 지원 안함
- 시간대: UTC 기준
- 실행 시간 제한: 함수 실행 시간 제한 적용
Solution
1. vercel.json Cron 설정
{
"crons": [
{
"path": "/api/cron/daily-backup",
"schedule": "0 2 * * *"
},
{
"path": "/api/cron/weekly-report",
"schedule": "0 9 * * 1"
},
{
"path": "/api/cron/monthly-cleanup",
"schedule": "0 0 1 * *"
}
]
}2. Cron 함수 구현
// app/api/cron/daily-backup/route.js
import { NextResponse } from 'next/server';
export async function GET(request) {
// 시크릿 키 검증
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
// 백업 작업 실행
await performBackup();
return NextResponse.json({
success: true,
timestamp: new Date().toISOString(),
});
} catch (error) {
console.error('Backup failed:', error);
return NextResponse.json(
{ error: 'Backup failed' },
{ status: 500 }
);
}
}
async function performBackup() {
// 데이터베이스 백업 로직
console.log('Starting backup...');
}3. 스케줄 표현식
// cron-schedules.js
export const schedules = {
// 매분 실행
everyMinute: '* * * * *',
// 매시간 실행
everyHour: '0 * * * *',
// 매일 아침 9시
dailyAt9AM: '0 9 * * *',
// 매주 월요일
weeklyMonday: '0 9 * * 1',
// 매월 1일
monthlyFirst: '0 0 1 * *',
// 평일 매일
weekdays: '0 9 * * 1-5',
// 주말
weekends: '0 10 * * 0,6',
};4. Cron 작업 모니터링
// lib/cron-monitor.js
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
export async function logCronExecution(jobName, status, duration) {
const log = {
jobName,
status,
duration,
timestamp: Date.now(),
};
await redis.lpush('cron-logs', JSON.stringify(log));
await redis.ltrim('cron-logs', 0, 999);
return log;
}
export async function getCronStats() {
const logs = await redis.lrange('cron-logs', 0, 49);
const parsed = logs.map(log => JSON.parse(log));
const stats = {
total: parsed.length,
success: parsed.filter(log => log.status === 'success').length,
failed: parsed.filter(log => log.status === 'failed').length,
avgDuration: parsed.reduce((sum, log) => sum + log.duration, 0) / parsed.length,
};
return stats;
}5. 알림 설정
// lib/cron-alerts.js
export async function sendAlert(message, level = 'info') {
// Slack 알림
if (process.env.SLACK_WEBHOOK_URL) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `[Cron ${level.toUpperCase()}] ${message}`,
}),
});
}
// 이메일 알림 (SendGrid 등)
if (level === 'error' && process.env.SENDGRID_API_KEY) {
await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SENDGRID_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
personalizations: [{ to: [{ email: process.env.ADMIN_EMAIL }] }],
from: { email: 'noreply@example.com' },
subject: `Cron Job Alert: ${message}`,
content: [{ type: 'text/plain', value: message }],
}),
});
}
}6. Cron 작업 테스트
// scripts/test-cron.js
async function testCronJob(path) {
const response = await fetch(`https://your-app.vercel.app${path}`, {
headers: {
'Authorization': `Bearer ${process.env.CRON_SECRET}`,
},
});
const result = await response.json();
console.log('Cron job result:', result);
return result;
}
// 테스트 실행
testCronJob('/api/cron/daily-backup');Lessons Learned
- 시크릿 키 관리: Cron 작업의 시크릿 키는 환경 변수로 관리해야 합니다.
- 에러 핸들링: Cron 작업 실패 시 알림을 받을 수 있도록 설정해야 합니다.
- 모니터링: Cron 작업 실행 이력을 모니터링하면 문제를 조기에 발견할 수 있습니다.
- 테스트: Cron 작업을 주기적으로 테스트하여 올바르게 동작하는지 확인해야 합니다.
- 플랜 확인: Vercel 플랜에 따라 Cron Jobs 지원 여부가 다를 수 있습니다.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.