TechFeedTechFeed
Cloud & DevOps

FUNCTION_INVOCATION_TIMEOUT, 서버리스 시간, maxDuration | 로컬은 되는데 배포만 끊기면?

FUNCTION_INVOCATION_TIMEOUT은 로컬 코드가 틀린 게 아니라 버셀 서버리스가 허용한 실행 시간을 넘겨 함수를 끊은 줄입니다. 노트북에는 한도가 없고 프리뷰 라우트에는 있습니다. maxDuration, 토스 웹훅 200 먼저, 카카오 콜백 쪼개기, P2024와 시간 한도 구분. Next.js, 버셀, 1인 개발자 기준. 2026년 9월 Vercel·Next.js·토스 웹훅 문서.

by

FUNCTION_INVOCATION_TIMEOUT은 로컬 코드가 틀린 게 아니라, 버셀 서버리스가 허용한 실행 시간을 넘겨 플랫폼이 함수를 끊은 줄입니다. 노트북에선 12초가 넘어가도 끝나고, 프리뷰만 10초 근처에서 잘리면 그 한도를 먼저 보세요.


토스 웹훅은 짧은 시간 안에 200을 기대합니다. 카카오 콜백에서 디비와 외부 API를 한 함수에 몰아 넣으면 프리뷰에서 이 줄이 납니다.


함수를 더 돌리기 전에, 기본 시간과 maxDuration, 그리고 요청 안에서 무엇을 기다렸는지부터 가릅니다. 근거는 Vercel 함수 제한Next.js 라우트 설정에 있습니다.


로컬은 되는데 배포만 끊기는 이유

노트북에는 시간 한도가 없고, 버셀 함수에는 있습니다. 로컬 next dev는 프로세스가 살아 있는 한 기다립니다. 배포된 라우트 핸들러는 플랜과 maxDuration이 정한 초에 도달하면 플랫폼이 강제 종료합니다.


로그에 FUNCTION_INVOCATION_TIMEOUT이 있으면 예외를 던진 게 아니라 시간으로 잘린 겁니다. 디비 쿼리가 느린지, 외부 API가 안 오는지, 한 요청에 일을 몰았는지는 그다음 질문입니다.


연결이 안 열린 거절과 자리도 다릅니다. ECONNREFUSED는 수신자가 없고, 타임아웃은 수신자는 있는데 제한 시간 안에 일을 못 끝낸 줄입니다. 거절은 ECONNREFUSED를, 디비가 호스트까지 안 열리면 P1001을 보세요.


먼저 기억할 것 | 로컬에서 오래 걸려도 성공한 코드가 프리뷰에서 죽는 첫 후보는 함수 실행 시간입니다. 콘솔 에러 본문보다 버셀 함수 로그의 Duration을 먼저 보세요.


로컬 넥스트는 기다리고 버셀 함수는 시간 한도에 잘리는 개념 이미지
노트북에는 없는 실행 시간 한도가 배포 함수에는 있다

플랜과 maxDuration을 어디에 적나

기본 시간과 올릴 수 있는 상한은 플랜마다 다릅니다. 문서 숫자는 바뀌니, 지금 프로젝트 플랜의 Duration 표를 기준으로 적으세요. 코드의 maxDuration이 플랜 상한을 넘으면 상한에서 잘립니다.


역할실수
기본 Duration설정 없이 적용되는 초로컬 12초 성공을 배포도 된다고 믿음
maxDuration그 라우트만 초를 올림플랜 상한을 넘는 숫자
vercel.json경로별 함수 설정App Router 파일 설정과 혼동
route segmentexport const maxDuration페이지에만 넣고 API 라우트엔 안 넣음

App Router 라우트 핸들러는 그 파일에 export const maxDuration = 30처럼 초를 적습니다. Next.js 라우트 세그먼트 설정 문서가 이 필드를 설명합니다. 페이지 서버 컴포넌트에만 넣고 app/api/webhook/route.js에는 안 넣으면, 웹훅만 기본 시간에 잘립니다.


app/api/webhook/route.js 시간 한도
export const maxDuration = 30 export const runtime = 'nodejs' export async function POST(req) { const body = await req.json() // 토스 웹훅: 먼저 200을 줄 수 있게 검증만 빠르게 return Response.json({ ok: true }) }

토스 웹훅 10초를 지키는 쪼개기

상대가 기다리는 시간과 버셀 한도는 별개입니다. 토스 웹훅은 짧은 시간 안에 2xx를 기대합니다. 함수 한도를 60초로 올려도, 토스가 먼저 포기하면 재전송이 쌓입니다.


패턴은 단순합니다. 서명 검증과 수신 확인을 먼저 하고 200을 준 뒤, 무거운 일(메일, 외부 정산, 큰 디비 집계)은 큐나 별도 함수로 넘깁니다. 한 요청 안에서 카카오 API와 토스 조회와 프리즈마 트랜잭션을 직렬로 기다리면 프리뷰에서 잘리기 쉽습니다.


연결 풀이 바닥나면 시간은 더 늘어납니다. 함수가 디비 칸을 못 받아 기다리다가 한도에 닿으면, 로그에는 타임아웃만 남고 원인은 P2024입니다. 풀 쪽은 P2024를 보세요. CORS로 브라우저가 막힌 줄과 섞지 마세요. 웹훅은 서버가 서버를 때리므로 CORS 대상이 아닙니다. CORS는 프리플라이트 글입니다.


  • [ ] 버셀 함수 로그에서 Duration이 한도에 닿았는지 봤다
  • [ ] 웹훅 라우트 파일에 maxDuration을 넣었는지 확인했다
  • [ ] 토스처럼 상대 제한이 더 짧으면 200을 먼저 주게 쪼갰다
  • [ ] 한 요청에 외부 API를 직렬로 기다리지 않게 바꿨다
  • [ ] 디비 풀 고갈(P2024)과 함수 시간 한도를 가렸다

토스 웹훅이 짧은 시간 안에 200을 받고 무거운 일은 뒤로 넘기는 흐름 이미지
함수 한도를 올려도 토스가 먼저 기다림을 그만두면 재전송이 쌓인다

스트리밍, 백그라운드와 혼동하지 않기

응답을 흘려 보내는 것과 실행 한도는 다른 칸입니다. 스트리밍은 첫 바이트를 빨리 줄 수 있지만, 함수가 살아 있는 총 시간은 여전히 한도를 받습니다. 긴 AI 응답을 라우트 안에서 끝까지 기다리면 같은 타임아웃이 납니다.


백그라운드로 착각하는 실수도 많습니다. 200을 준 뒤 await 없이 무거운 일을 이어가도, 플랫폼이 함수를 얼리면 그 일은 중간에 끊깁니다. 확실히 남기려면 큐, 크론, 또는 별도 호출이 필요합니다.


카카오 로그인 콜백에서 프로필 저장, 세션 쿠키, 관리자 알림을 한 번에 기다리면 프리뷰에서 잘리기 쉽습니다. 콜백은 세션만 만들고, 프로필 보강은 로그인 이후 페이지에서 느슨히 채우세요. 쿠키 속성이 얽이면 SameSite도 함께 봅니다.


한도만 올리는 건 임시 | maxDuration을 최대로 올려도 토스 10초와 사용자 체감은 그대로입니다. 기다리는 일을 쪼개는 쪽이 재전송과 과금을 줄입니다.


로그에서 시간으로 잘린 줄 읽기

버셀 대시보드 함수 로그의 Duration과 상태 코드부터 봅니다. 한도 초와 Duration이 같으면 코드 예외보다 시간입니다. 그다음 그 요청이 호출한 디비, 카카오, 토스 URL을 로그로 나눠 찍으세요.


로컬에서 재현하려면 일부러 지연을 넣기보다, 프리뷰 로그의 타임스탬프를 보는 편이 정확합니다. 노트북은 CPU와 디비 왕복이 달라 12초가 4초로 보이기도 합니다.


로그의미다음
FUNCTION_INVOCATION_TIMEOUT실행 시간 한도이 글
P2024디비 풀 대기연결 풀 글
P1001디비 TCP 실패P1001 글
ECONNREFUSED빈 포트연결 거절 글

버셀 함수 로그에서 Duration이 한도에 닿아 타임아웃으로 표시되는 화면 이미지
Duration이 한도 초와 같으면 예외보다 시간으로 잘린 줄이다

참고 자료

공식 문서 다섯 곳을 기준으로 적었습니다.



내부 연계: ECONNREFUSED, P1001, P2024, CORS, 쿠키 SameSite


인용한 동작은 2026년 9월 공개 문서 기준입니다.


자주 묻는 질문

로컬에선 끝나는데 프리뷰만 타임아웃입니다.

로컬 개발 서버에는 버셀 함수 한도가 없습니다. 프리뷰 Duration이 한도 초와 같은지 로그에서 보세요. 라우트 파일에 maxDuration을 넣었는지도 확인하세요.


maxDuration을 최대로 올리면 해결되나요?

잠깐은 됩니다. 토스 웹훅처럼 상대가 더 짧게 기다리면 재전송이 남습니다. 검증 후 200을 먼저 주고 무거운 일은 뒤로 넘기는 편이 안전합니다.


페이지에는 maxDuration을 넣었는데 API가 죽습니다.

세그먼트 설정은 그 파일에만 적용됩니다. 웹훅은 app/api/.../route.js에 따로 export 해야 합니다. 페이지 값만 올리고 API를 안 건드리면 기본 시간에 잘립니다.


200을 준 뒤 백그라운드로 일하면 되나요?

await 없이 이어가도 함수가 얼면 그 일은 끊깁니다. 남기려면 큐나 별도 호출이 필요합니다. 응답만 빠르게 하고 일이 끝났다고 보면 데이터가 빠집니다.


P2024와 같이 보이면 무엇을 먼저 보나요?

풀에서 칸을 못 받아 기다리다가 함수 한도에 닿은 경우입니다. 연결 풀을 줄이고, 함수마다 새 클라이언트를 만들지 마세요. 시간만 올리면 같은 대기열이 남습니다.


카카오 콜백도 같은 타임아웃이 납니다.

콜백 한 요청에 토큰, 프로필, 디비, 알림을 직렬로 기다리면 프리뷰에서 잘리기 쉽습니다. 세션만 만들고 프로필은 이후 페이지에서 채우세요.


FUNCTION_INVOCATION_TIMEOUT은 버셀이 허용한 초를 넘겨 함수를 끊었다는 뜻입니다. Duration을 한도와 대조하고, 웹훅은 200을 먼저 준 뒤 무거운 일을 쪼개세요. 관련 글: 연결 거절, 연결 풀, P1001.


FUNCTION_INVOCATION_TIMEOUTmaxDuration서버리스버셀웹훅토스카카오넥스트타임아웃개발자

함께 보면 좋은 문제 해결

EXPLORE / Cloud & DevOps

이어서 읽어보기

전체 토픽 둘러보기