제한과 정책
Deplite는 워크플로우 폭주를 방지하기 위해 여러 종류의 제한을 제공해요.
정의는 워크플로우 YAML의 limits: 블록에 적어요.
Cooldown
마지막 실행 후 지정한 시간 동안 다음 실행을 막아요.
limits:
- type: cooldown
after: 5m # 5분
on: success # success: 성공한 실행만 카운트
# any: 모든 실행 카운트after: Go duration 문법 (30s,5m,1h,2h30m)on:success— 성공 후에만 쿨다운 시작 (실패는 즉시 재시도 가능)any— 어떤 결과든 쿨다운 시작 (실패 폭주 방지)
리밋이 발동하면 Job은 status: rejected, rejectReason: rate_limited, limitType: cooldown로 기록돼요.
응답에 retryAfterSeconds도 함께 들어와요.
Token Bucket
용량과 충전 속도를 가진 토큰 버킷이에요. 실행마다 1개 토큰을 소비해요.
limits:
- type: bucket
capacity: 5 # 최대 토큰 5개
refill: 1/1h # 1시간마다 1개 충전capacity: 1 이상의 정수refill:<count>/<duration>형식 (1/10m,5/1h)
리밋 발동 시 응답 형태는 cooldown과 같지만 limitType: bucket이에요.
한 워크플로우에 두 종류 함께 쓰기
limits:
- type: cooldown
after: 1m
- type: bucket
capacity: 10
refill: 1/5mcooldown 1개 + bucket 1개까지 허용돼요.
“1분에 한 번 이하 + 시간당 12회 이하”처럼 짧은 보호와 긴 보호를 함께 걸 때 좋아요.
상태 저장 위치
리밋 상태는 Agent 디스크의 ./logs/limits/<workflow-name>.json에 저장돼요.
Agent를 재시작해도 상태가 유지돼요.
{
"cooldown_last_finish_at": "2026-05-31T10:30:00Z",
"cooldown_last_finish_status": "success",
"bucket_tokens": 2.5,
"bucket_updated_at": "2026-05-31T10:29:45Z",
"bucket_init": true
}force 우회
리밋을 명시적으로 우회해야 할 때(긴급 핫픽스 등)는 force: true로 호출해요.
curl -X POST .../triggers/<id>/run-manual \
-d '{"ref": "main", "force": true, "forceReason": "hotfix CVE-2026-X"}'- owner 권한 + 워크플로우의
force_allowed: true(기본)일 때만 허용 - Job 기록에
forced: true,forceReason,bypassedLimits로 남음 - Audit log에
trigger.force_run액션이 기록
큐잉
Agent는 동시에 처리할 수 있는 Job 수에 제한이 있어요(기본 큐 100).
큐가 가득 차면 새 Job은 즉시 status: rejected, rejectReason: queue_full로 거부돼요.
이때는 Agent를 여러 대로 늘리거나 워크플로우당 동시성을 제어하세요.
중복 제거 (Idempotency)
Webhook 호출 시 Idempotency-Key 헤더를 보내면, 같은 키의 요청은 첫 Job을 그대로 돌려줘요.
curl -X POST .../triggers/<id>/run \
-H "Idempotency-Key: deploy-2026-05-31-001" \
-d '{"ref": "main"}'같은 키로 2번째 호출이 와도 새 Job이 만들어지지 않고, 첫 Job의 jobId를 반환해요.
서버 측 토큰 레이트 리밋
API Token 발급 시 분/시간/일당 호출 횟수를 제한할 수 있어요.
{
"name": "CI/CD",
"scopeType": "trigger",
"triggerIds": ["..."],
"rateLimitPerMinute": 10,
"rateLimitPerHour": 100,
"rateLimitPerDay": 1000
}워크플로우 단위 리밋(Agent 측)과 토큰 단위 리밋(서버 측)은 서로 독립적이에요.
실전 시나리오
시나리오 A — 폭주하는 webhook 보호
PR 머지마다 배포 webhook이 호출되는데, 여러 PR이 동시에 머지되면 동시 빌드가 폭주해요.
name: deploy-prod
limits:
- type: cooldown
after: 90s
- type: bucket
capacity: 5
refill: 1/3m90초 안에 두 번째 호출이 들어오면 rejected. 또 시간당 약 20회 이상은 bucket이 마름.
시나리오 B — 헬스체크는 무조건 5분 간격
name: healthcheck
limits:
- type: cooldown
after: 4m
on: any # 실패해도 즉시 재시도 금지
steps:
- run: curl -fsS https://app.example.com/healthCron 트리거를 1분 간격으로 걸어도 안전해요. on: any 덕분에 실패 폭주가 막혀요.
시나리오 C — 긴급 핫픽스로 리밋 우회
평소엔 30분 cooldown이지만 보안 패치는 즉시 배포해야 해요.
curl -X POST https://app.deplite.io/api/triggers/<id>/run-manual \
-H "Authorization: Bearer $JWT" \
-d '{
"ref": "hotfix/cve-2026-x",
"force": true,
"forceReason": "CVE-2026-X 패치 — Sec팀 승인"
}'Job 기록:
{
"id": "j-9ab2",
"status": "running",
"forced": true,
"forceReason": "CVE-2026-X 패치 — Sec팀 승인",
"bypassedLimits": ["cooldown"]
}Audit log:
2026-05-31T13:42:18Z trigger.force_run
actor: user_alice
trigger: deploy-prod
metadata: { ref: "hotfix/cve-2026-x", reason: "..." }거부 응답 형태
리밋에 걸리면 webhook 호출은 즉시 rejected를 받아요.
{
"jobId": "j-9ab3",
"status": "rejected",
"rejectReason": "rate_limited",
"limitType": "cooldown",
"retryAfterSeconds": 158
}대시보드 Jobs 화면에서도 동일한 정보가 보여요. 재시도 자동화 시 retryAfterSeconds만큼 대기 후 다시 호출하면 돼요.