Preview Bản nháp chờ review — title, nội dung, link có thể sửa trước khi bỏ nhãn.

Kho đếm SKU trên kệ. Hệ async hay quên đếm thứ tương đương: việc dang dở — mỗi Promise chưa settle, mỗi HTTP handler chưa return, mỗi message chưa ack, mỗi connection đang mượn.

Mỗi cái giữ vốn: heap, native buffer, file descriptor, slot DB pool, timer, continuation trên event loop. Gọi là in-flight inventory: hàng đã “xuất kho tài nguyên” nhưng chưa thu hồi.

Demo (không trần vs trần inventory): unbounded vs pool — in-flight & memory proxy (bài unbounded đã có). Ý inventory = cách đọc metric đó như nợ, không chỉ “bug leak”.

Vì sao metaphor inventory hữu ích

  • Leak classic = quên release. Inventory = có thể không leak mà vẫn chết vì nhận việc nhanh hơn hoàn thành.
  • Scale CPU không giảm inventory nếu bottleneck là chờ I/O — chỉ chất thêm SKU.
  • On-call hỏi “đang ôm bao nhiêu?” thay vì chỉ “CPU bao nhiêu?”.

Map sang bài đã có

Không đếm / không trần  → unbounded in-flight (OOM im)
Trần số đang bay        → pool concurrency
Đầy thì tín hiệu ngược  → backpressure
Đầy + không control client → load shedding
Unit rẻ (coroutine)     → vẫn 1 SKU / task
Orphan sau timeout      → inventory “ma” (cancellation)

Đếm gì (thực dụng)

in_flight_requests      HTTP server / client concurrent
in_flight_jobs          worker concurrency / BullMQ active
db_pool_active          connection đang checkout
queue_unacked           delivered chưa ack
event_loop_lag / delay  proxy “nợ” trên 1 thread JS
goroutines / tasks      runtime-specific

Chọn tài nguyên hẹp nhất làm ngân sách: thường DB pool hoặc memory, không phải “CPU còn 40%”.

Ngân sách inventory

  1. Đặt trần K (pool) khớp downstream (vd. DB max_connections / instances).
  2. Khi full: queue có bound, hoặc backpressure, hoặc 503 shed — đừng accept vô hạn.
  3. Phân biệt rate limit vs pool: N/sec start ≠ max đang bay.
  4. Alert trên inventory và age (oldest in-flight), không chỉ error rate.

Ví dụ số

Handler concurrency 200
DB pool 20
→ 180 request “chạy” thực ra xếp chờ connection
→ p99 nổ, CPU có thể rảnh
→ inventory app cao + pool active = 20 (hẹp)

Sửa: giảm handler concurrency / tăng pool có chủ đích /
     fail-fast khi acquire timeout
(xem connection-pool-exhaustion)

Không chỉ “bớt Promise.all”

Fire-and-forget void job(), consumer prefetch lớn, upload stream không backpressure, webhook fan-out… đều là cách nhận SKU không kiểm soát. Coroutine/async làm SKU rẻ hơn thread — dễ nhồi nhiều hơn trước khi đau.

Đọc tiếp

Một câu để nhớ

In-flight là hàng đang giữ vốn — không bound là phá sản im lặng.
Đếm, đặt trần, từ chối hoặc chậm lại khi đầy.