대기열 작업자 옵저버빌리티
대기열 깊이는 대기 중인 작업의 양을 나타냅니다. 대기열 대기는 각 작업의 백로그 비용을 나타냅니다. 실행 기간은 작업자가 실행하는 데 소요되는 시간을 나타냅니다. 최종 결과와 재시도 횟수는 작업이 결국 성공할지 여부를 나타냅니다.
뒤처진 큐, 느린 종속성, 재시도 폭풍 또는 사라진 작업자와 정상적인 트래픽 버스트를 구별하려면 네 가지 신호가 모두 필요합니다.
꼬리 백분위수는 평균으로 처리할 수 있는 느린 작업을 나타냅니다.
전제 조건
- Telemetry API 키
- 대기열에 추가, 시작 및 최종 결과 경계를 노출하는 작업자
- 안정적인 논리적 작업 식별자 및 낮은 카디널리티 작업 이름
- 각 중요 작업 유형의 예상 완료 창
스냅샷과 결과를 별도로 모델링
서로 다른 질문에 답하므로 두 가지 이벤트 형태를 사용하십시오.
| 이벤트 | 곡물 | 사용 |
|---|---|---|
queue_snapshot |
하나의 샘플링 시간에 하나의 큐 | 현재 깊이, 사용 가능한 작업자, 가장 오래된 대기 연령 |
background_job_completed |
논리적 작업당 하나의 최종 결과 | 대기, 실행 기간, 재시도, 성공, 영구 실패 |
스냅샷은 샘플링된 상태이므로 시간에 따른 대기열 깊이를 합산하지 마세요. 최종 결과는 완료된 작업이므로 시작했다가 사라진 작업을 찾을 수 없습니다. 중단된 작업 감지가 필요한 경우 경량 job_started 및 job_finished 수명 주기 이벤트를 추가합니다.
터미널 이벤트 계약 정의
백그라운드 작업 완료 스키마를 시작점으로 사용하세요.
| 필드 | 의미 |
|---|---|
event_id |
중복 제거에 사용되는 고유한 터미널 이벤트 |
job_id |
시도 전반에 걸쳐 공유되는 안정적인 논리적 작업 식별자 |
job_name |
제한된 작업 유형(동적 페이로드 또는 ID는 아님) |
queue_name |
작업을 실행한 큐 |
account_id |
결과에 영향을 받는 가명 계정 |
attempt_count |
최종 시도를 포함한 총 시도 횟수 |
queue_wait_ms |
첫 번째 실행 대기열에 추가 |
duration_ms |
터미널 시도 실행 기간 |
status |
success 또는 영구 error |
release |
작업자 또는 애플리케이션 버전 |
작업 인수, 자격 증명, 이메일 주소, 문서 내용 및 원시 예외 텍스트를 이벤트에서 제외하세요. 운영자에게 오류 범주가 필요한 경우 제한된 error_type를 사용합니다.
결과 경계 계측
JavaScript SDK를 설치하고 초기화합니다.
npm install telemetry-sh
import telemetry from "telemetry-sh";
telemetry.init("YOUR_API_KEY");
동일한 시계로 대기열 삽입, 첫 번째 시작 및 터미널 완료를 측정합니다. 성공 후 하나의 터미널 행을 내보내거나 소진된 후 다시 시도하십시오.
async function processJob(job) {
const startedAtMs = Date.now();
let terminalAttemptStartedAtMs = startedAtMs;
let attemptCount = 0;
try {
const result = await runWithRetry(async () => {
attemptCount += 1;
terminalAttemptStartedAtMs = Date.now();
return performJob(job);
});
await telemetry.log("background_job_completed", {
event_id: crypto.randomUUID(),
job_id: job.id,
job_name: job.name,
queue_name: job.queue,
account_id: job.accountId,
attempt_count: attemptCount,
queue_wait_ms: startedAtMs - job.enqueuedAtMs,
duration_ms: Date.now() - terminalAttemptStartedAtMs,
total_elapsed_ms: Date.now() - startedAtMs,
status: "success",
release: process.env.APP_RELEASE ?? "unknown"
});
return result;
} catch (error) {
await telemetry.log("background_job_completed", {
event_id: crypto.randomUUID(),
job_id: job.id,
job_name: job.name,
queue_name: job.queue,
account_id: job.accountId,
attempt_count: attemptCount,
queue_wait_ms: startedAtMs - job.enqueuedAtMs,
duration_ms: Date.now() - terminalAttemptStartedAtMs,
total_elapsed_ms: Date.now() - startedAtMs,
status: "error",
error_type: classifyJobError(error),
release: process.env.APP_RELEASE ?? "unknown"
});
throw error;
}
}
이 예에서는 duration_ms에 터미널 시도를 유지하고 total_elapsed_ms에 전체 재시도 정책 벽 시간을 유지합니다. 재시도 라이브러리가 이러한 경계를 다르게 보고하는 경우 문서화된 두 가지 의미를 유지하면서 타이머를 조정하세요.
원격 분석 호출은 작업의 지속성 상태 변경을 따라야 합니다. 이미 성공한 작업을 비즈니스 부작용의 재시도로 전환하지 않고 애플리케이션이 텔레메트리 전달 실패를 처리하는 방법을 결정합니다. 동일한 터미널 이벤트가 다시 전송될 때 텔레메트리 전달 재시도에서 event_id를 유지합니다.
샘플 대기열 상태
대기열의 권한 있는 상태에서 고정된 간격으로 스냅샷을 수집합니다.
async function recordQueueSnapshot(queue) {
const state = await queue.inspect();
await telemetry.log("queue_snapshot", {
event_id: crypto.randomUUID(),
queue_name: queue.name,
depth: state.waitingCount,
active_workers: state.activeWorkers,
oldest_wait_ms: state.oldestEnqueuedAtMs
? Date.now() - state.oldestEnqueuedAtMs
: 0,
release: process.env.APP_RELEASE ?? "unknown"
});
}
의미 있는 백로그를 감지할 수 있을 만큼 간격을 자주 유지하되, 동일한 샘플이 이벤트 볼륨을 지배할 정도로 너무 자주 간격을 유지하지 마십시오. 0 깊이를 0으로 기록합니다. 그것을 생략하지 마십시오.
런타임과 별도의 큐 대기
이 쿼리는 일반 대기와 테일 대기를 테일 실행 기간과 비교합니다.
SELECT
job_name,
COUNT(*) AS jobs,
approx_percentile_cont(queue_wait_ms, 0.50) AS p50_wait_ms,
approx_percentile_cont(queue_wait_ms, 0.95) AS p95_wait_ms,
approx_percentile_cont(duration_ms, 0.95) AS p95_run_ms
FROM background_job_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY job_name
HAVING COUNT(*) >= 20
ORDER BY p95_wait_ms DESC;
정상 런타임의 높은 p95 대기는 용량, 예약, 우선 순위 지정 또는 버스트 처리를 가리킵니다. 작업 코드 또는 종속성에 대한 일반적인 대기 지점이 있는 높은 런타임. 둘 다 함께 증가하면 느린 작업으로 인해 작업자 용량이 소모되고 백로그가 생성된다는 의미일 수 있습니다.
재시도 및 최종 실패 측정
터미널 이벤트는 하나의 논리적 작업을 기록하므로 attempt_count > 1는 최소한 한 번의 재시도 후에 작업이 복구되었음을 의미합니다.
SELECT
job_name,
COUNT(*) AS jobs,
SUM(CASE WHEN attempt_count > 1 THEN 1 ELSE 0 END) AS retried_jobs,
SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) AS permanent_failures,
100.0 * SUM(CASE WHEN attempt_count > 1 THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS retried_job_rate_pct,
100.0 * SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS permanent_failure_rate_pct
FROM background_job_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
GROUP BY job_name
ORDER BY permanent_failure_rate_pct DESC, retried_job_rate_pct DESC;
대신 시도당 하나의 행을 내보내는 경우 attempt 필드와 안정적인 job_id를 사용하세요. 분모와 해석이 달라집니다. 재시도가 실수로 별도의 고객 작업으로 계산되지 않도록 모든 쿼리 옆에 행 단위를 문서화하세요.
중단되거나 손실된 작업 감지
터미널 전용 테이블은 장기 실행 작업과 작업자 충돌 후 손실된 작업을 구별할 수 없습니다. 동일한 job_id를 사용하여 job_started와 job_completed 또는 job_failed를 내보낸 다음 왼쪽 조인을 사용하여 터미널 이벤트 없이 시작을 찾습니다.
임계값은 작업별로 지정되거나 예상 완료 창에서 파생되어야 합니다. 장기 실행 작업에는 하트비트 이벤트가 필요할 수 있습니다. 최신 행이 오탐지를 생성하지 않도록 이벤트 전달 지연에 대한 짧은 유예 기간을 추가합니다.
특정 작업이 중단되었다는 증거로 대기열 깊이를 처리하는 대신 전체 중단된 백그라운드 작업 쿼리를 사용하세요.
배달 못한 편지, 우선 순위 및 종료에 대한 설명
재시도 정책이 소진되고 작업이 배달 못한 편지 대기열에 들어갈 때 고유한 터미널 범주 또는 이벤트를 기록합니다. 원본 job_id에 연결된 새로운 운영 작업으로 재생을 추적합니다. 원래 실패를 자동으로 다시 작성하지 마십시오.
작업자를 교체할 수 없는 경우 대기열 또는 우선순위별로 용량 신호를 분할합니다. 정상적인 대량 대기열은 전체 평균에서 차단된 중요 대기열을 숨길 수 있습니다.
배포 및 종료 중:
- 직원을 해고하기 전에 새 작업 수락을 중단합니다.
- 문서화된 배수 간격을 허용합니다.
- 의도적인 재큐와 실행 실패를 구별합니다.
- 논리적
job_id및 증분 시도 상태를 유지합니다. - 시작된 모든 작업이 결국 터미널 이벤트를 생성하는지 확인하십시오.
대시보드 구축
백그라운드 작업 대시보드 예시는 SQL, 합성 결과 및 해석을 제공합니다. 프로덕션 대시보드에는 다음이 포함되어야 합니다.
- 현재 대기열 깊이 및 대기열별 가장 오래된 대기 기간;
- p50 및 p95 대기열은 작업 이름별로 대기합니다.
- 작업 이름별 p95 실행 기간;
- 작업 재시도 및 영구 실패율;
- 안전한 상관관계 식별자가 있는 현재 중단된 작업;
- 배포를 변경 사항과 비교할 수 있도록 릴리스별로 볼륨을 조정합니다.
추세에 대해서는 완전한 시간 버킷을 사용하십시오. 순위율 이전에 최소 거래량 규칙을 설정하세요. 조용한 대기열에 있는 단일 실패한 작업은 해당 워크플로가 중요한 경우에만 운영상 중요합니다. 그렇지 않으면 백분율만으로 대용량 회귀보다 순위가 높아서는 안 됩니다.
임계값뿐만 아니라 응답에 대한 알림
각 알림을 소유자 및 작업에 연결합니다.
| 상태 | 가능성 있는 질문 | 첫 번째 응답 |
|---|---|---|
| 깊이와 가장 오래된 대기 상승 | 수요가 용량을 초과합니까? | 도착률, 작업자, 우선순위, 종속성 상태 확인 |
| 대기가 안정적인 동안 실행 시간이 늘어납니다. | 작업 코드나 종속성이 느려졌나요? | 릴리스 및 오류 카테고리 비교 |
| 재시도율 상승 | 일시적인 오류가 작업을 증폭시키나요? | 제한된 오류 유형 및 공급자 상태 검사 |
| 영구 고장 증가 | 회복이 소진되었나요? | 영향을 받은 계정 및 데드 레터 상태 식별 |
| 시작에는 터미널 이벤트가 없습니다. | 작업자 충돌이나 계측이 사라졌나요? | 작업자, 하트비트, 작업 상태 검사 |
하나의 불완전한 버킷에 대한 페이징을 피하세요. 지속적인 위반 또는 심각한 터미널 오류가 필요하고 임계값을 워크플로의 예상 완료 시간에 맞춰 유지하세요.
프로덕션 전 검증
다음을 위해 픽스처를 실행하십시오:
- 첫 시도 성공;
- 재시도 후 성공;
- 영구적인 실패 및 데드-레터 항목;
- 중복 이벤트 전달;
job_started이후 작업자 충돌;- 심장 박동이 있는 장기 실행 작업;
- 정상적으로 배출되는 대기열 버스트;
- 배포 종료 및 다시 대기열.
논리적 작업 수, 시도 횟수, 대기열 대기, 실행 기간, 누락된 터미널 이벤트 및 영향을 받은 계정 수를 확인합니다. 또한 텔레메트리 오류가 멱등성이 아닌 비즈니스 작업을 재생할 수 없는지 확인하십시오.
다음 단계
큐 대기 레시피, 백그라운드 작업 재시도 비율 레시피, 중단된 백그라운드 작업 레시피 및 백그라운드 작업 모니터링 사용 사례를 계속 진행하세요.