바닐라 비동기 배칭 가이드
비동기 배칭은 배칭 가이드에서 설명한 수집 및 트리거 동작을 유지하면서 Promise 결과, 재시도, 오류 콜백, 실패 항목 추적, 진행 중인 작업 제어 기능을 추가합니다.
하나의 비동기 작업에서 수집된 여러 항목을 함께 처리해야 할 때 사용합니다. 각 항목마다 자체 실행이 필요하거나 동시성을 제한해야 한다면 비동기 큐를 사용합니다.
비동기 배칭의 작동 방식
설정된 트리거 중 하나가 발생할 때까지 항목을 수집합니다.
add A ─── add B ─── add C
│ │ │
└─ wait reset └─ maxSize reached
│
└─ execute [A, B, C]
다음 조건에서 배치가 실행됩니다.
- 길이가
maxSize에 도달합니다. getShouldExecute(items, batcher)가true를 반환합니다.wait밀리초 동안 새 항목이 들어오지 않습니다.
maxSize와 wait의 기본값은 모두 Infinity이므로 하나 이상의 트리거를 설정하거나 flush()를 직접 호출합니다. 항목을 추가할 때마다 대기 타이머가 다시 시작됩니다. 이 타이머는 가장 오래된 항목의 최대 수명이 아니라 유휴 기간을 측정합니다.
빠른 시작
항목 추가 작업만 필요하다면 asyncBatch를 사용합니다.
import { asyncBatch } from '@tanstack/pacer'
const addAnalyticsEvent = asyncBatch(
async (events: Array<AnalyticsEvent>) => {
const response = await fetch('/api/analytics/batch', {
method: 'POST',
body: JSON.stringify(events),
})
if (!response.ok) throw new Error('Batch failed')
return response.json()
},
{ maxSize: 20, wait: 1000 },
)
addAnalyticsEvent(event)
생명주기 메서드, 콜백, 상태가 필요하다면 AsyncBatcher를 사용합니다.
import { AsyncBatcher } from '@tanstack/pacer'
const batcher = new AsyncBatcher(sendEvents, {
maxSize: 20,
wait: 1000,
onSuccess: (result, batch) => {
console.log('Sent:', batch.length, result)
},
onError: (error, batch) => {
console.error('Failed batch:', batch, error)
},
})
batcher.addItem(event)
const result = await batcher.flush()
Promise 결과
flush()는 배치 함수의 결과를 반환하며 특정 배치를 기다리는 가장 명확한 방법입니다.
addItem()도 Promise를 반환하지만 개별 항목의 결과 수신 수단으로 취급해서는 안 됩니다.
- 해당 추가로
maxSize에 도달하거나getShouldExecute를 충족하면 그 Promise가 트리거된 실행을 소유하고 배치 결과로 이행됩니다. - 대기 타이머만 예약한다면 그 Promise는 나중의 배치 결과 없이 이행됩니다.
- 다른 항목이 추가되면 타이머가 재설정되고 함께 실행되는 항목이 달라질 수 있습니다.
모든 추가 작업에서 최종 배치 결과를 관찰해야 한다면 onSuccess, onError, onSettled를 사용합니다.
배치 경계와 겹치는 작업
배처는 비동기 함수를 호출하기 전에 현재 항목을 복사하고 지웁니다. 해당 함수가 활성 상태인 동안 추가된 항목은 새 배치에 수집됩니다.
execute [A, B] ───────────────── finish
add C ─── add D ─── execute [C, D] ─── finish
첫 배치가 끝나기 전에 두 번째 배치의 트리거가 발생하면 두 배치 함수가 겹칠 수 있습니다. AsyncBatcher에는 동시성 옵션이 없습니다. 실행이 겹치면 안전하지 않은 경우 배처 외부에서 배치 실행을 직렬화하거나 완성된 배치를 비동기 큐를 통해 전달합니다.
오류 및 실패한 항목
비동기 배처는 다음 콜백을 제공합니다.
onSuccess(result, batch, batcher)는 성공 후 실행됩니다.onError(error, batch, batcher)는 배치의 재시도가 실패한 후 실행됩니다.onSettled(batch, batcher)는 어느 결과든 완료된 후 실행됩니다.onItemsChange(batcher)는 항목이 추가되거나 실행을 위해 제거될 때 실행됩니다.
onError가 없으면 throwOnError의 기본값이 true이므로 실패할 때 flush() 또는 크기 트리거를 발생시킨 addItem()이 거부됩니다. onError를 제공하면 이 기본값이 false로 바뀌고 Promise는 undefined로 이행됩니다.
항목은 실행 전에 대기 중인 컬렉션에서 제거됩니다. 실패한 배치는 자동으로 큐에 다시 추가되지 않습니다. 해당 항목은 failedItems에 추가되며 clear()나 이후 실행이 그 컬렉션을 지울 때까지 peekFailedItems()를 통해 사용할 수 있습니다.
const failed = batcher.peekFailedItems()
for (const item of failed) {
saveForManualRecovery(item)
}
멱등성이 없는 작업에서는 실패한 배치를 다시 제출하기 전에 서버 결과를 확인합니다.
배치 재시도
각 배치 실행의 재시도를 asyncRetryerOptions로 설정합니다.
const batcher = new AsyncBatcher(sendEvents, {
maxSize: 20,
wait: 1000,
asyncRetryerOptions: {
maxAttempts: 3,
backoff: 'exponential',
baseWait: 500,
jitter: 0.2,
},
})
maxAttempts에는 첫 시도가 포함되며 모든 재시도는 복사된 동일한 배치를 받습니다. 부수 효과가 있는 작업을 재시도하기 전에 비동기 재시도 가이드를 참고합니다.
플러시, 취소 및 지우기
flush()는 대기 중인 타이머를 지우고 현재 항목을 즉시 실행합니다.cancel()은 대기 중인 타이머를 지우지만 수집된 항목은 유지합니다.clear()는 수집된 항목과 실패한 항목을 제거하지만 예약된 타이머는 지우지 않습니다.peekAllItems()는 현재 수집된 항목의 복사본을 반환합니다.
clear()는 타이머를 그대로 두므로 빈 타이머가 남아서는 안 된다면 cancel()을 호출한 다음 clear()를 호출합니다.
batcher.cancel()
batcher.clear()
나중에 실행된 타이머나 flush()가 항목을 찾지 못하면 배치 함수가 호출되지 않습니다.
활성 작업 중단
abort()는 활성 재시도기를 중단합니다. 대기 중인 배치를 취소하거나 수집된 항목을 제거하지는 않습니다. 취소가 전파되도록 배처의 신호를 기반 API에 전달합니다.
const batcher = new AsyncBatcher(
async (events: Array<AnalyticsEvent>) => {
return fetch('/api/analytics/batch', {
method: 'POST',
body: JSON.stringify(events),
signal: batcher.getAbortSignal() ?? undefined,
})
},
{ maxSize: 20, wait: 1000 },
)
batcher.abort()
실행이 겹칠 때 특정 실행의 신호가 필요하다면 executeCount를 getAbortSignal()에 전달합니다.
안전하게 재설정하기
reset()은 기본 상태를 복원하지만 예약된 타이머를 지우지 않으며 활성 기반 작업의 중지를 보장하지도 않습니다. 완전히 정리해야 한다면 먼저 생명주기 메서드를 사용합니다.
batcher.cancel()
batcher.abort()
batcher.reset()
설정 및 상태
wait에는 숫자 또는 배처 인스턴스를 받는 함수를 지정할 수 있습니다. setOptions()는 새 옵션을 병합하고 asyncBatcherOptions()는 재사용할 수 있고 타입 검사를 거친 옵션 객체를 생성합니다.
배처를 일시 중지하는 데 started를 사용하지 않습니다. 현재 아무 작업도 하지 않으므로 모든 addItem() 호출이 설정된 트리거를 평가합니다.
애플리케이션이 유지한 일부 상태를 복원하려면 부분 스냅샷을 initialState로 전달합니다. 이 스냅샷은 기본값과 병합됩니다. 지속 가능한 필드만 복원합니다. 대기 중인 타이머와 활성 실행은 복원되지 않습니다.
일반적인 상태는 다음과 같습니다.
items,size,isPending: 다음 배치와 해당 타이머의 상태입니다.isExecuting: 배치가 실행 중인 것으로 보고되는지 나타냅니다.lastResult: 가장 최근의 성공 결과입니다.failedItems와totalItemsFailed: 실패 추적 정보입니다.successCount,errorCount,settleCount: 배치 결과 횟수입니다.totalItemsProcessed: 성공한 배치 실행의 항목 수입니다.
전체 옵션과 상태 타입은 AsyncBatcher API 레퍼런스를 참고합니다.