Files
2nd/10_Wiki/Topics/Domain_Programming/Coding/Backend_Cron_Patterns.md
T
Antigravity Agent c24165b8bc refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게
[공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류.
문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인).

- Topic_Programming → Domain_Programming (내부 구조 보존)
- Topic_Graphic → Domain_Design
- Topic_Business → Domain_Product
- Topic_General → Domain_General
- _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning),
  Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing)
- 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서)
- 빈 폴더 정리 (memory/procedures)
- 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:05:56 +09:00

4.3 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
backend-cron-patterns Cron / Scheduled Jobs — 분산 / 멱등 / 락 Coding draft B conceptual 2026-05-09 2026-05-09
backend
cron
scheduler
idempotency
vibe-coding
language applicable_to
TS / SQL / Redis
Backend
scheduled job
periodic
cron expression
distributed lock
leader election

Cron / Scheduled Jobs

분산 환경 cron = leader 락 + 멱등 안 하면 N대 서버에 N번 실행. DB row lock / Redis lock / Kubernetes CronJob / 클라우드 매니지드 스케줄러 중 1개. 매 실행 멱등.

📖 핵심 개념

  • Single instance: 한 시점에 한 곳만 실행.
  • Idempotent: 두 번 실행돼도 결과 동일.
  • Catch-up: 시간 지나가면 늦게라도 실행할지 / skip 할지.
  • At-least-once: 보통 OK, 단 멱등 보장 필요.

💻 코드 패턴

node-cron / BullMQ repeat

import { Queue } from 'bullmq';

const q = new Queue('reports');
await q.add('daily', {}, {
  repeat: { pattern: '0 9 * * *', tz: 'America/New_York' }, // 매일 9시 NY
  jobId: 'daily-report', // 같은 jobId = 중복 등록 방지
});

DB-based lock

-- locks 테이블
CREATE TABLE job_locks (
  name TEXT PRIMARY KEY,
  locked_by TEXT,
  locked_at TIMESTAMPTZ,
  expires_at TIMESTAMPTZ
);

-- 시도
INSERT INTO job_locks (name, locked_by, locked_at, expires_at)
VALUES ('daily-report', $hostname, NOW(), NOW() + INTERVAL '10 minutes')
ON CONFLICT (name) DO UPDATE
SET locked_by = $hostname, locked_at = NOW(), expires_at = NOW() + INTERVAL '10 minutes'
WHERE job_locks.expires_at < NOW()
RETURNING *;
async function runWithLock(name: string, fn: () => Promise<void>) {
  const got = await db.tryLock(name, hostname());
  if (!got) return; // 다른 노드가 잡음
  try { await fn(); } finally { await db.releaseLock(name); }
}

Redis-based lock (Redlock)

import Redlock from 'redlock';

const lock = await redlock.acquire(['locks:daily-report'], 60_000);
try { await runDaily(); } finally { await lock.release(); }

Idempotency

async function dailyReport(date: string) {
  const id = `report:${date}`;
  if (await db.exists(id)) return; // 이미 만들어짐
  const r = await build(date);
  await db.put(id, r);
}

Catch-up

// 마지막 실행 시간 저장 → 차이만큼 반복
const last = await db.get('cursor:reports');
for (let d = nextDay(last); d <= today(); d = nextDay(d)) {
  await dailyReport(d);
  await db.put('cursor:reports', d);
}

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: daily-report
spec:
  schedule: "0 9 * * *"
  concurrencyPolicy: Forbid # 이전 job 안 끝났으면 새거 skip
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  startingDeadlineSeconds: 600 # 10분 안에 시작 안되면 skip
  jobTemplate:
    spec:
      backoffLimit: 2
      template:
        spec:
          containers:
          - name: report
            image: app:latest
            args: ["node", "dist/jobs/daily-report.js"]
          restartPolicy: OnFailure

Cron expression (UTC vs local)

0 9 * * *      # 매일 9:00 UTC (서버 타임존이 UTC면)
0 9 * * 1-5    # 평일 9시
*/15 * * * *   # 15분마다
0 0 1 * *      # 매월 1일

🤔 의사결정 기준

환경 추천
Vercel / Cloudflare Vercel Cron / CF Cron
AWS EventBridge → Lambda
K8s CronJob + concurrencyPolicy: Forbid
단일 Node node-cron + DB lock
큐 기반 BullMQ repeat / Sidekiq
정확한 시간 보장 X drift 감수 또는 클라우드

안티패턴

  • N대 서버에 cron 동시 실행: 단일 락 또는 leader 만.
  • Idempotency 미보장: 재실행 시 데이터 망가짐.
  • 타임존 confusion: UTC 명시 또는 cron expression 에 tz.
  • Long-running job 크론에서: 다음 실행 충돌. 큐로 보내기.
  • Catch-up 무한: 24시간 정지 후 돌아오면 1440번 실행.
  • Job 결과 남기지 않음: 실패 추적 불가.
  • At-most-once 가정: 분산 = 항상 at-least-once.

🤖 LLM 활용 힌트

  • 항상 멱등 + 락 + 결과 기록.
  • K8s CronJob = concurrencyPolicy: Forbid.
  • 시간 = UTC 또는 명시 tz.

🔗 관련 문서