외부 API에서 데이터 긁어와서 저장하는 배치를 setInterval로 1분마다 돌리고 있어요. 평소엔 몇 초면 끝나는데, 외부 API가 느려지거나 데이터가 많은 날엔 한 번 도는 데 2~3분씩 걸립니다.
그러면 이전 실행이 아직 안 끝났는데 다음 1분 tick이 와서 또 실행되고, 그게 쌓이면서 같은 데이터를 중복 저장하거나 외부 API rate limit에 걸려버려요.
setInterval(async () => {
await syncFromExternal() // 오래 걸리면 겹침
}, 60_000)겹치지 않게, 이전 게 완전히 끝난 다음에 다음 걸 돌리려면 어떻게 해야 하나요?
댓글 4
제일 깔끔한 건 setInterval을 버리고 재귀 setTimeout으로 바꾸는 겁니다. 한 번 실행이 완전히 끝난 다음에 다음 타이머를 거는 방식이에요.
async function loop() {
try { await syncFromExternal() }
catch (e) { console.error(e) }
finally { setTimeout(loop, 60_000) }
}
loop()
이러면 실행이 2분 걸리면 그게 끝나고 1분 뒤에 다음 게 도니 절대 안 겹칩니다. 간격의 의미가 '시작 간격 1분'에서 '끝난 뒤 1분 쉼'으로 바뀌는 건 알아두세요.
setInterval을 꼭 유지하고 싶으면 실행 중 플래그로 겹침만 막을 수도 있어요. let running = false 두고 콜백 진입 시 if (running) return; running = true; 하고 finally에서 running = false. 이건 tick 자체는 정시에 오되 이미 돌고 있으면 그 tick을 건너뜁니다.
어느 쪽이든 catch/finally를 꼭 넣으세요. 안에서 에러가 나면 재귀 방식은 다음 스케줄이 안 걸리고, 플래그 방식은 running이 true로 박혀서 영영 멈추는 사고가 납니다. 재스케줄과 플래그 해제를 finally에서 하는 게 그래서 중요해요.