Node JS 에서 나타났던 상황이지만 Java 등 모든 WAS서버에서 나올수 있는 상황
상황
DB 커넥션 풀이 꽉 차서 API가 504 뜨고, 완전 가벼운 API도 덩달아 느려지고, SequelizeConnectionAcquireTimeoutError까지 터짐. 원인 파보니 트랜잭션 하나를 안 닫고 있었음.
문제 코드
이미 있으면 그거 리턴, 없으면 새로 생성 패턴에서 나왔던 실수임.
const findOrCreateRoom = async (userId: string) => {
const transaction = await sequelize.transaction() // 커넥션 하나 확보
try {
const existing = await Room.findOne({ where: { userId } })
if (existing) {
return existing // ⚠️ 여기서 그냥 끝. commit도 rollback도 안 함
}
const created = await Room.create({ userId }, { transaction })
await transaction.commit()
return created
} catch (err) {
await transaction.rollback()
throw err
}
}
existing이 있는 경우(=제일 자주 타는 경로)마다 트랜잭션을 열어놓고 return 해버림. 커넥션이 풀로 안 돌아가고, DB에는 idle in transaction 세션으로 계속 쌓임. 이 함수 호출될 때마다 하나씩 새서, 풀(예: max 10개) 금방 바닥남. → 이후 요청들은 커넥션 못 받아서 줄줄이 타임아웃.
배운 것
1. 트랜잭션 열었으면 모든 return 경로가 commit/rollback으로 끝나야 함
if (existing) {
await transaction.commit() // 또는 rollback — 아무튼 닫아야 함
return existing
}
2. { transaction } 안 넘긴 쿼리는 그 트랜잭션이랑 상관없이 따로 커넥션 잡아씀
// 이러면 findOne이 위 transaction과 별개로 커넥션 하나 더 쓴다
const existing = await Room.findOne({ where: { userId } })
// 이래야 같은 커넥션 재사용
const existing = await Room.findOne({ where: { userId }, transaction })
(단, Sequelize.useCLS()로 CLS 세팅해두면 자동으로 물려서 안 넘겨도 됨 — 안 쓰는 프로젝트라면 매번 명시해야 함)
3. commit()은 실패해도 트랜잭션을 끝내버림 그래서 catch에서 무조건 rollback() 부르면, 이미 끝난 트랜잭션에 롤백 시도하다가 새 에러(Transaction cannot be rolled back because it has been finished with state: commit)
터지면서 원래 에러가 로그에서 사라짐. commit 시도했으면 플래그 세워서 롤백 스킵하는 게 안전함.
let done = false
try {
// ...
done = true
await transaction.commit()
} catch (err) {
if (!done) await transaction.rollback()
throw err
}
4. 동시 요청이 트랜잭션을 나눠쓰는 건 아님 const transaction = await sequelize.transaction()은 함수 호출마다 새로 생기는 지역변수라 요청끼리 안 섞임. 대신 동시에 열 수 있는 트랜잭션(=커넥션) 개수가 pool 크기로 제한되는 게 진짜 문제임. 그 이상 몰리면 뒤 요청은 커넥션 기다리다 타임아웃.
한 줄 요약
트랜잭션은 연 사람이 반드시 닫아야 함.
return
으로 일찍 빠져나가는 경로일수록 깜빡하기 쉬우니까 특히 조심.
'TIL' 카테고리의 다른 글
| 느린 Pod로 요청이 가지 않게 할 수 있을까? (0) | 2026.09.07 |
|---|---|
| Kubernetes Pod별 리소스 모니터링 구성 (0) | 2026.09.03 |
| Vite 외부 공격 요청을 보면서 정리한 보안 체크 5가지 (0) | 2026.08.31 |
| k3s 노드 DiskPressure 원인 추적 및 조치 (0) | 2026.08.27 |
| Docker 디스크 부족 시 확인 방법 (0) | 2026.08.26 |