Thứ ba, 06/01/2026 Ngọc Hân

Mytel MagicWheel – HikariPool Connection Timeout do Open-EntityManager-In-View (WebService)

1. Mô tả lỗi

Trong một số thời điểm tải cao, hệ thống ghi nhận lỗi:

HikariPool - Connection is not available, request timed out after 30000ms
(total=100, active=100, idle=0, waiting=…)

Biểu hiện:

  • Một số request bị timeout

  • Giao dịch không được xử lý hoặc xử lý thất bại

  • Log xuất hiện lỗi JDBCConnectionException / HikariPool timeout

  • Ảnh hưởng trực tiếp đến trải nghiệm người dùng

Lỗi thường xuất hiện ở các luồng xử lý gọi sang hệ thống MPS và chờ phản hồi dài (người dùng xác nhận USSD).


2. Phạm vi ảnh hưởng

  • Các API có luồng xử lý:

    • Truy vấn database qua JPA Repository

    • Sau đó gọi external system (MPS) với thời gian chờ dài (20s ~ 50s)

  • Khi có nhiều request đồng thời:

    • Connection pool bị sử dụng hết

    • Các request khác không lấy được JDBC connection

Ảnh hưởng:

  • TPS của hệ thống giảm

  • Một phần request thất bại trong thời gian ngắn

  • Có thể gây gián đoạn dịch vụ khi tải cao


3. Nguyên nhân

3.1. Nguyên nhân gốc

Nguyên nhân không phải do database chậm hay pool size nhỏ, mà do:

JDBC connection bị giữ quá lâu trong vòng đời HTTP request


3.2. Luồng xử lý TRƯỚC khi fix

(spring.jpa.open-in-view = true – mặc định Spring Boot)

Mô tả

  • Spring Boot mặc định bật Open-EntityManager-In-View (OEIV)

  • EntityManager được mở ngay khi request bắt đầu

  • JDBC connection bị giữ xuyên suốt HTTP request

  • Bao gồm cả thời gian chờ external MPS

Sơ đồ luồng xử lý:

 

Hệ quả:

 

  • Mỗi request giữ 1 JDBC connection trong 20–50s

  • N request đồng thời → N connection bị chiếm

  • Khi pool đạt giới hạn:

    • Request mới không lấy được connection → timeout

👉 Đây là tình trạng thiếu connection do bị giữ quá lâu, không phải leak vĩnh viễn.


3.3. Luồng xử lý SAU khi fix

(spring.jpa.open-in-view = false)

Mô tả

  • EntityManager chỉ tồn tại trong phạm vi repository / transaction

  • JDBC connection được giải phóng ngay sau DB operation

  • External MPS call không giữ connection

Sơ đồ luồng xử lý:

Kết quả:

  • JDBC connection chỉ bị giữ trong thời gian rất ngắn (ms)

  • External call dài không ảnh hưởng connection pool

  • Hệ thống ổn định hơn khi tải cao


3.4. Lưu ý quan trọng về hành vi mặc định của Spring Boot

  • Tất cả các phiên bản Spring Boot (1.x → 3.x) đều mặc định bật:

    spring.jpa.open-in-view = true
  • Spring Boot:

    • Không log warning

    • Không cảnh báo cấu hình

    • Không tự động disable

Điều này dẫn đến:

  • Ứng dụng chạy bình thường khi tải thấp

  • Lỗi chỉ bộc lộ khi:

    • Tải cao

    • External call có latency lớn

  • Rất dễ bị bỏ qua nếu không hiểu rõ vòng đời EntityManager và JDBC connection

👉 Với REST API / microservice, OEIV là anti-pattern và cần được tắt chủ động.


4. Phương án xử lý

4.1. Tắt Open-EntityManager-In-View

spring:
   jpa:
     open-in-view: false

Tác dụng:

  • EntityManager chỉ tồn tại trong phạm vi repository / transaction

  • JDBC connection được giải phóng ngay sau khi kết thúc thao tác DB

  • Không còn giữ connection trong thời gian chờ external MPS


4.2. Bật giám sát connection leak (phòng ngừa)

spring:
  datasource:
    hikari:
      leak-detection-threshold: 20000
  • Log cảnh báo nếu 1 connection bị giữ > 20s

  • Không ảnh hưởng hiệu năng

  • Giúp phát hiện sớm nếu lỗi tương tự tái diễn trong tương lai


4.3. Nguyên tắc coding bắt buộc

  • Không gọi external API bên trong transaction

  • Không để transaction bao quanh logic chờ external response

  • Chỉ thao tác DB trong scope ngắn nhất có thể

  • Tách rõ:

    • DB operation

    • External API call


5. Bài học rút ra

  1. JDBC connection là tài nguyên rất hạn chế, cần được giải phóng càng sớm càng tốt

  2. Open-EntityManager-In-View là anti-pattern đối với REST API và microservice

  3. External call có latency cao không được giữ transaction / connection DB

  4. Các lỗi kiến trúc kiểu này:

    • Không lộ ở môi trường tải thấp

    • Chỉ xuất hiện khi TPS cao + latency lớn

  5. Luôn bật cơ chế giám sát để:

    • Phát hiện sớm

    • Tránh lỗi tái diễn trong tương lai