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

Event loop giỏi I/O non-block. CPU hash lớn, image resize, driver chỉ có API sync → ôm loop = chết concurrency.

Offload: chạy việc đó trên thread/process pool; loop chỉ await “khi xong”.

Offload cái gì

  • CPU-bound: nén, crypto nặng, parse khổng lồ, ML infer nhỏ.
  • Sync I/O bắt buộc: legacy SDK block.
  • Không offload: I/O đã async gọn — chỉ thêm hop và contention pool.

Pool size = ngân sách

Pool N threads
= tối đa N blocking in-flight
= inventory (xem inflight-inventory)

N quá lớn → thrash, contest DB
N quá nhỏ → queue offload dài, p99 nổ

Align với DB pool và CPU cores (CPU-bound ~ cores; I/O-block pool có thể > cores).

Fake async

// Vẫn kẹt loop — heavy chạy TRƯỚC khi await nhường
await Promise.resolve(heavySync())

// Node worker_threads (ý)
const { Worker } = require('worker_threads')
function offload(workerFile, data) {
  return new Promise((resolve, reject) => {
    const w = new Worker(workerFile, { workerData: data })
    w.on('message', resolve)
    w.on('error', reject)
  })
}
await offload('./heavy.js', payload)
// hoặc pool worker tái sử dụng — đừng new Worker mỗi request không bound

Offload ≠ parallel magic

Đưa sang 1 worker = khỏi kẹt loop, chưa chắc nhanh hơn wall-clock nếu một việc. Nhiều core: data/task parallel.

Một câu

Offload cứu loop; pool size vẫn là ngân sách blocking in-flight.
await không biến sync thành non-block nếu heavy chạy trên loop.