2026. 7. 16.
Vercel FUNCTION_INVOCATION_TIMEOUT, 로그에서 먼저 볼 것
Vercel 배포 뒤 504 FUNCTION_INVOCATION_TIMEOUT이 뜰 때 런타임 로그와 구간별 시간 측정으로 느린 외부 호출, 응답 누락, 반복문을 구분하는 점검 순서입니다.

Vercel 배포는 Ready인데 API를 호출하자 504: FUNCTION_INVOCATION_TIMEOUT이 뜬다면 빌드부터 다시 할 문제가 아니다. 배포된 함수가 설정된 실행 시간 안에 HTTP 응답을 끝내지 못한 상태다. 먼저 실패한 요청 하나의 Runtime Logs를 열고, 마지막으로 끝난 작업 다음 구간을 찾는다.
확인 순서는 짧다. 요청 시작 로그, 외부 API나 데이터베이스 호출 전후 로그, 응답 반환 로그를 한 요청 안에서 맞춘다. 시작은 있는데 종료가 없는 구간이 첫 조사 대상이다. 시간 제한 숫자를 올리기 전, 끝나지 않은 await부터 찾는 것이 핵심이다.
504는 빌드가 아니라 실행 중 응답이 끝나지 않은 상태다
Vercel의 FUNCTION_INVOCATION_TIMEOUT 공식 설명은 함수 호출이 허용된 실행 시간을 넘었을 때 이 오류가 발생한다고 밝힌다. 공식 점검 항목은 크게 네 갈래다.
- 외부 API나 데이터베이스 요청이 늦게 끝난다.
- 조건문 일부에서 HTTP 응답을 반환하지 않는다.
- 반복문이나 재귀 호출이 끝나지 않는다.
- 상위 서비스 오류나 처리되지 않은 예외 때문에 정상 종료 경로에 도달하지 못한다.
따라서 npm run build가 통과했는지보다 어느 요청이 어느 실행 구간에서 멈췄는지를 먼저 확인해야 한다. 공개 URL 자체가 404: NOT_FOUND라면 함수 실행 이전 문제일 수 있으니 Vercel 배포 성공 후 404 범위별 점검표로 루트, 하위 경로, 도메인을 먼저 나눈다. 빌드 단계에서 실패했다면 Vercel 배포 실패 로그를 읽는 순서가 더 가까운 출발점이다.
한 요청의 마지막 완료 로그에서 조사 범위를 자른다
Vercel Runtime Logs 공식 문서에 따르면 프로젝트의 Logs 화면은 production과 preview 함수 호출을 보여준다. 상태 코드, route, RequestId, 함수 실행 시간, 메모리, 이벤트 타임라인, 외부 요청, console.log 메시지를 한 요청 단위로 확인할 수 있다.
대시보드에서 프로젝트를 연 뒤 Logs로 이동한다. Environment를 production, Status Code를 504, Route를 문제가 난 API 경로로 좁힌다. 같은 요청의 RequestId를 열어 Events와 Outgoing Requests를 본다. 연결된 프로젝트에서 CLI를 쓴다면 Vercel CLI logs 문서의 필터를 적용할 수 있다.
npx vercel logs --environment production --status-code 504 --since 1h
이 명령은 최근 한 시간의 production 504 요청을 찾는다. 프로젝트가 연결되지 않았다면 먼저 npx vercel link가 필요하다. 로그가 아예 없다면 보고 있는 배포 환경과 branch, route가 맞는지 다시 확인한다.
코드에는 한 요청에서 서로 짝이 맞는 구간 로그를 남긴다. 토큰, 쿠키, 요청 본문 전체는 기록하지 않는다.
const startedAt = Date.now();
console.log("profile-fetch:start");
const response = await fetch(PROFILE_API_URL);
console.log("profile-fetch:end", {
status: response.status,
durationMs: Date.now() - startedAt,
});
start는 있는데 end가 없다면 fetch가 끝나지 않았거나 그 사이에서 예외가 났다. 둘 다 있는데 최종 응답 로그가 없다면 다음 변환, 데이터베이스 기록, 응답 생성 구간으로 이동한다. 마지막 완료 로그 다음 한 구간만 조사하면 AI에게도 수정 범위를 작게 줄 수 있다.
외부 호출에는 자체 제한과 실패 응답을 둔다
Vercel의 느린 함수 디버깅 가이드는 production 로그에서 느린 함수를 찾고, 실행 시간을 잰 뒤, 외부 API 지연과 함수 설정을 확인하도록 안내한다. 외부 호출이 끝날 때까지 플랫폼 제한에 맡기면 사용자는 원인을 알 수 없는 504만 받는다.
Next.js Route Handler에서는 AbortController로 외부 호출에 애플리케이션 수준의 제한을 둘 수 있다. 아래 8_000밀리초는 복사해 고정할 정답이 아니라 동작을 보여주는 예시다. 실제 값은 외부 서비스의 정상 응답 시간과 화면이 기다릴 수 있는 시간을 재서 정한다.
export async function GET() {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 8_000);
const startedAt = Date.now();
try {
console.log("upstream:start");
const upstream = await fetch(PROFILE_API_URL, {
signal: controller.signal,
});
console.log("upstream:end", {
status: upstream.status,
durationMs: Date.now() - startedAt,
});
if (!upstream.ok) {
return Response.json({ error: "upstream_failed" }, { status: 502 });
}
return Response.json(await upstream.json());
} catch (error) {
console.error("upstream:error", {
name: error instanceof Error ? error.name : "unknown",
durationMs: Date.now() - startedAt,
});
return Response.json({ error: "upstream_timeout" }, { status: 504 });
} finally {
clearTimeout(timer);
}
}
이 코드는 외부 호출이 오래 걸리면 플랫폼이 함수를 강제 종료하기 전에 애플리케이션이 의도한 오류 응답을 돌려준다. try, catch, 조건 분기마다 return이 있는지 확인한다. forEach(async () => ...)처럼 기다림이 분명하지 않은 구조, 종료 조건 없는 while, 자기 자신을 다시 호출하는 route도 함께 찾는다.
원인을 줄인 뒤에만 리전과 maxDuration을 바꾼다
정상 작업 자체가 길다는 측정이 있다면 함수 설정을 본다. Vercel Functions 공식 문서는 함수와 데이터 소스의 거리가 멀면 네트워크 왕복 시간이 늘 수 있다고 설명한다. Runtime Logs의 Function 위치와 데이터베이스 리전을 비교한다.
Vercel maxDuration 설정 문서는 Next.js 13.5 이상에서 route 파일에 maxDuration을 내보내는 방법을 안내한다.
export const maxDuration = 30;
이 숫자도 보편적인 권장값이 아니다. 현재 프로젝트의 Fluid compute 사용 여부와 요금제에 따라 기본값과 상한이 달라진다. 설정 화면과 최신 공식 표를 확인한다. 응답 누락, 무한 루프, 느린 상위 서비스를 남긴 채 maxDuration만 늘리면 실패가 늦어질 뿐이다.
정상적으로 오래 걸리는 작업이 HTTP 응답 시간 안에 끝날 필요가 없다면 요청과 작업을 분리하는 구조를 검토한다. 사용자에게 작업 접수 응답을 먼저 돌려주고, 별도 큐나 장기 실행 워크플로가 처리한 뒤 상태를 조회하게 하는 방식이다.
재검증은 의도한 응답과 완성된 시간 로그로 끝낸다
수정 뒤에는 같은 입력으로 production 또는 preview 요청을 다시 보낸다. 통과 기준은 화면에서 504가 사라졌다는 느낌이 아니다.
- 요청 시작과 모든 핵심 외부 호출의 종료 로그가 한 RequestId에 남는다.
- 성공이면 의도한 2xx, 상위 서비스 실패면 코드에서 정한 4xx 또는 5xx가 반환된다.
- 외부 호출 시간과 전체 함수 시간이 기록된다.
- 재시도 횟수와 반복문의 종료 조건을 설명할 수 있다.
- 정상 실행이 설정된 duration 안에서 끝나는지 확인한다.
종료 로그가 계속 사라지면 그 바로 앞 호출의 URL, 리전, 연결 제한, 상위 서비스 상태를 운영자와 함께 확인한다. 오늘 할 첫 행동은 실패한 요청 하나를 다시 만들고 start와 end 로그가 어디에서 갈리는지 표시하는 것이다.
이 글은 AI 코딩과 개발 학습의 일반 정보 제공 목적입니다. 도구, 모델, 커리큘럼, 요금은 버전과 시점에 따라 달라질 수 있으므로 실습이나 도입 전 공식 문서와 최신 릴리스 노트를 확인하세요.
다음으로 읽을 기사
같은 흐름으로 이어 읽기 좋은 기사만 추려 보여줍니다.
첫 번째 댓글을 남겨보세요
여러분의 생각이 다른 독자에게 도움이 됩니다.
댓글 0
이 글을 읽은 독자들의 생각을 나눠보세요.