lifecarelog
백엔드

Workers 응답 후 로그가 사라질 때 ctx.waitUntil 점검법

Workers 엣지 게이트웨이에서 응답 뒤 로그 전송이 누락되는 floating promise 문제와 ctx.waitUntil 적용 기준을 정리해요.

4분 읽기

Workers를 API 게이트웨이로 쓰면 요청을 빠르게 돌려준 뒤 접근 로그나 분석 이벤트를 보내고 싶어져요. 그런데 fetch()를 호출만 하고 기다리지 않는 floating promise는 응답이 끝난 뒤 실행 환경이 정리되면서 완료 전에 멈출 수 있어요. 오류가 화면에 드러나지 않아 더 찾기 어렵습니다.

직접 최소 예제를 만들어 보니, return Response.json() 뒤에 남긴 로그 전송은 요청 응답과 별개의 작업이에요. 응답 코드가 200이어도 외부 로그 저장이 끝났다는 뜻은 아니었습니다. 1개의 요청을 처리할 때 응답 경로와 비동기 전송 경로, 2개를 분리해서 봐야 해요.

요청 수신API 응답 반환ctx.waitUntil로 로그 작업 유지

핸들러 안에서 반드시 기다려야 하는 작업은 await로 처리합니다. 반면 사용자 응답을 늦추지 않아도 되는 로그 전송, 캐시 갱신, 분석 이벤트처럼 후속 처리할 일은 ctx.waitUntil()에 전달해요.

export default {
  async fetch(request, env, ctx) {
    const logTask = sendLog({
      method: request.method,
      path: new URL(request.url).pathname,
    }).catch((error) => console.error('log failed', error))
 
    ctx.waitUntil(logTask)
 
    return Response.json({ ok: true })
  },
}

적용해 봤더니 핵심은 promise를 “생성”하는 것과 실행 수명을 “등록”하는 것이 다르다는 점이었어요. ctx.waitUntil(logTask)는 후속 작업을 런타임에 알리지만, 외부 서비스 장애까지 해결하지는 않습니다. 그래서 catch를 붙여 실패를 관측하고, 로그 전송 실패가 API 응답 자체를 실패시키지 않도록 경계를 나눠야 해요.

테스트해 보면 3단계로 확인할 수 있어요. 첫째, 정상 요청 1건에서 응답과 로그 저장을 각각 확인해요. 둘째, 로그 저장 대상이 느리거나 실패하는 상황에서도 API 응답이 유지되는지 봐요. 셋째, 실패 로그에 요청 식별값과 결과를 남겨 재시도 정책의 근거를 확보해요.

  • await는 응답 전 완료
  • waitUntil은 응답 후 유지
  • catch는 실패 관측

돌려 보니 이 구분은 플랜비(plan-b)처럼 여러 운영 이벤트를 기록하는 서비스에서도 유용했어요. 다만 회비 변경처럼 데이터 일관성이 필요한 작업까지 무조건 후속 처리로 보내면 안 돼요. API의 성공 응답 조건에 포함되는 DB 쓰기는 await하고, 부가 로그만 ctx.waitUntil으로 분리하는 4가지 기준을 팀 규칙으로 남겨두면 조용한 누락을 줄일 수 있어요.

#Cloudflare Workers#ctx.waitUntil#백엔드

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.