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
- Đặt trần K (pool) khớp downstream (vd. DB max_connections / instances).
- Khi full: queue có bound, hoặc backpressure, hoặc 503 shed — đừng accept vô hạn.
- Phân biệt rate limit vs pool: N/sec start ≠ max đang bay.
- 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
- Unbounded in-flight — anti-pattern.
- Batch vs pool — cách bound.
- Cancellation — đừng giữ inventory ma.
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.