이현석의 우체통

라라벨에서 배열 유효성 검증하다가 타임아웃이 났다

Maximum execution time of 60 seconds exceeded

센트리 알림이 울려 내용을 살펴보니 요청 처리에 60초가 초과되어 에러가 났습니다. 엔드포인트를 보니 매우 단순한 기능인데 왜 60초 씩이나 걸렸을까 의문이 들었어요.

에러가 발생한 위치를 살펴보았습니다.

Validator 에서 걸렸다는 점에 착안해 검색해보니 큰 배열을 유효성 검증할 때 시간이 오래 걸린다는 이야기가 있더군요. (관련 링크: https://github.com/laravel/ideas/issues/2212)

실험을 해보니 느린 것이 사실이었습니다. 배열 내의 각 항목을 검사하고자 할 때 아래와 같이 유효성 검사 규칙을 넣어주게 되는데,

$validator = Validator::make($request->all(), [
    'someArray.*' => 'integer',
]);

이러면 값을 하나하나 검증하기 때문에 양이 많이지면 느려질 수 밖에 없는 것이죠.

해결책

한 가지 해결책은 매우 큰 배열이 들어올 수도 있는 항목의 경우엔 개별 항목 유효성 검사 규칙을 사용하지 않고, 배열에 커스텀 유효성 검사 규칙을 적용하여 속도를 개선하는 것입니다.

$request->validate([
    'someArray' => ['array', new CustomRule]
    // 'someArray.*' => 'integer', <- 하나씩 검사하는 코드는 제거
]);

더 나은 해결책

더 나은 해결책은 애초에 대량 배열이 들어오지 않도록 배열의 최대 크기를 정해주는 것입니다.

$request->validate([
    'someArray' => ['array', 'max:1000'],
    'someArray.*' => 'integer',
]);

그러면 개별값들을 검사하는데 훨씬 부담이 적어지겠죠. 하지만 이미 발행되어 클라이언트가 사용 중인 API를 이런식으로 바꿔버리면 재앙이 발생하겠죠?

되도록 API를 처음 만들 때부터 최대 크기를 정하는 버릇을 들이는게 좋고, 커스텀 유효성 검사 규칙을 만들고 배열 자체에 적용하는 방식은 이미 API가 배포되어 수정하기 어려울 때 어쩔 수 없이 사용한다고 보시면 될 것 같습니다.

Exit mobile version