Ba cách, đi từ đơn giản tới bền vững:
1. Ghi kép (dual write) trong code. Sau khi commit DB thì gọi ES index luôn. Đơn giản nhưng không nguyên tử: DB commit xong mà ES lỗi thì hai bên lệch vĩnh viễn, không ai biết. Chỉ dùng cho hệ thống nhỏ, chấp nhận reindex lại.
2. Outbox + worker. Cùng transaction ghi bảng nghiệp vụ và ghi một dòng vào bảng outbox. Worker đọc outbox theo thứ tự, đẩy sang ES, đánh dấu đã xử lý, retry khi lỗi. Giữ được tính nguyên tử vì mọi thứ nằm trong một transaction Postgres.
3. CDC từ WAL (Debezium / logical replication). Không phải sửa code nghiệp vụ, bắt được cả thay đổi từ migration hay script tay. Đổi lại là thêm hạ tầng để vận hành.
Về độ trễ: Elasticsearch bản thân đã là near real-time — document chỉ tìm được sau khi refresh, mặc định 1 giây. Cộng thêm pipeline đồng bộ, độ trễ thực tế thường là vài giây. Đó là con số bình thường; đừng hứa "tức thì".
Hệ quả thiết kế phải nói rõ: sau khi người dùng tạo hoặc sửa bản ghi, nếu điều hướng sang trang danh sách chạy bằng search thì có thể chưa thấy bản ghi đó. Cách xử lý là đọc chi tiết trực tiếp từ Postgres (nguồn sự thật) và chỉ dùng ES cho tìm kiếm/lọc, kèm một job reindex định kỳ để bù các bản ghi trôi mất.