Next.js 14 App router mysql Too many connections 오류

te-ing·2024년 3월 24일
0

◼︎ 문제상황

Next.js를 사용하여 개발하던 중 MySQL 데이터베이스와의 통신 과정에서 "Too many connections" 오류가 발생했습니다.

해당 오류는 MySQL 데이터베이스 서버의 동시 연결 수 제한 초과로 인한 오류로, 일반적으로 connections이 설정한 수보다 많거나, 쿼리 실행 후 connection을 반환하지 않아 생기는 문제입니다.

하지만 connections는 매우 넉넉한 설정이었고, 쿼리 실행 후 Connection을 반환했음에도 문제가 계속해서 발생했습니다.


◼︎ 문제원인

Next.js ver.14는 개발 모드에서 API 경로를 매번 재구축하여 데이터베이스의 pool을 생성할 때 마다 트리거합니다. 이때 생성한 pool의 대한 경로가 달라져 connection이 정상적으로 반환되지 못해 발생하는 오류입니다.


◼︎ 해결방안

node 전역변수에 pool 경로를 선언하여 pool을 사용할때 마다 API 경로가 바뀌지 않도록 하여, 정상적으로 반환할 수 있도록 구현하였습니다.

import mysql, { Pool } from 'mysql2';
/**
 * check, globalObject, registerService
 * Next.js는 개발 모드에서 API 경로를 지속적으로 재구축하는데, initFn()의 경로를 전역으로 지정하여 변경되지 않도록 합니다.
 */
function check(it: false | (Window & typeof globalThis) | typeof globalThis) {
  return it && it.Math === Math && it;
}
const globalObject =
  check(typeof window === 'object' && window) ||
  check(typeof self === 'object' && self) ||
  check(typeof global === 'object' && global) ||
  (() => {
    return this;
  })() ||
  Function('return this')();

const registerService = (name: string, initFn: any) => {
  if (process.env.NODE_ENV === 'development') {
    if (!(name in globalObject)) {
      globalObject[name] = initFn();
    }
    return globalObject[name];
  }
  return initFn();
};

export let pool: Pool;

pool = registerService('mysql', () =>
  mysql.createPool({
    ...config
  }),
);

node의 전역변수 globalThis에 접근하기 위해서는 registerService를 사용하여 globalObject에 pool을 선언해야 하는데, 이때 globalThis의 polyfill을 위해 globalObject의 타입체크를 거칩니다.

위와 같은 과정으로 globalObject에 pool을 등록했다면, 서버 렌더링 시 globalObject에 pool의 존재여부를 확인하고, pool이 존재할 경우 해당 pool을 사용하여 API 경로가 바뀌지 않게 됩니다.



참고자료:
카카오페이지 웹 react 포팅 후기
Fix "too many connections" errors with database clients stacking in dev mode with Next.js

profile
병아리 프론트엔드 개발자🐣

0개의 댓글