Series Docker & Beanstalkd cho Laravel #3: Xây dựng Đội quân Worker "Bất tử" với Supervisor (Trạm cuối)
1. Tại sao không dùng lệnh Docker CMD mặc định?
Nhiều người mới thường chế một Container mới chuyên chạy Queue với lệnh cuối cùng trong Dockerfile là: CMD ["php", "artisan", "queue:work", "beanstalkd"]
Cách này hoạt động được, nhưng nó là một thảm họa tiềm ẩn:
- Không có độ dự phòng: Nếu đoạn code PHP bên trong Job ném ra một Fatal Error (VD: tràn RAM, hoặc chia cho 0), tiến trình queue:work sẽ chết. Docker Container sẽ lập tức bị tắt (Exit) và không ai xử lý Queue nữa.
- Thiếu sức mạnh song song (Concurrency): Bạn chỉ có 1 tiến trình xử lý từng Job một. Quá chậm cho hệ thống Metro!
Giải pháp chuẩn Enterprise là cài đặt Supervisor – Một hệ thống quản lý tiến trình kinh điển của hệ điều hành Linux – thẳng vào bên trong Container PHP.
2. Vũ trang Supervisor cho Container PHP
Hãy mở file Dockerfile dùng để build hình ảnh php-fpm của hệ thống lên, và thêm chỉ thị cài đặt thư viện supervisor:
# Sử dụng base image PHP của bạn
FROM php:8.2-fpm
# Cài đặt Supervisor cùng các thư viện thiết yếu
RUN apt-get update && apt-get install -y \
supervisor \
# ... (các thư viện khác)
# Tạo thư mục chứa file log cho các Worker
RUN mkdir -p /var/log/supervisor
# Chép file cấu hình của Supervisor từ mã nguồn vào Container
COPY ./docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Thay đổi lệnh khởi động mặc định (CMD) của Container.
# Thay vì chỉ chạy php-fpm, chúng ta chạy lệnh giám sát của Supervisor
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
Với cấu hình này, khi Container khởi chạy, Supervisor sẽ là kẻ nắm quyền sinh sát tối cao (PID 1).
3. Bản thiết kế Quân đoàn (Worker Blueprint)
Tiếp theo, hãy tạo một thư mục ./docker/supervisor/ trong source code gốc và tạo file supervisord.conf bên trong. Đây chính là "Binh pháp" quy định cách đội quân của bạn hoạt động:
[supervisord]
# Chạy ở chế độ foreground để Docker có thể theo dõi tiến trình
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
# 1. TIẾN TRÌNH LÕI: PHP-FPM (Phục vụ API cho Nginx)
[program:php-fpm]
command=php-fpm
autostart=true
autorestart=true
priority=5
stderr_logfile=/var/log/supervisor/php-fpm.err.log
stdout_logfile=/var/log/supervisor/php-fpm.out.log
# 2. ĐỘI QUÂN WORKER CHO BEANSTALKD
[program:laravel-worker]
# Lệnh yêu cầu worker làm việc. Nhớ set timeout nhỏ hơn TTR (Time-To-Run) của Beanstalkd
command=php /var/www/html/artisan queue:work beanstalkd --queue=hitachi_sync,default --sleep=3 --tries=3 --timeout=60 --max-time=3600
process_name=%(program_name)s_%(process_num)02d
# 🔥 ĐIỂM ĂN TIỀN NHẤT: Nhân bản thành 10 công nhân chạy song song!
numprocs=10
autostart=true
# Nếu công nhân chết do code lỗi hoặc tràn RAM? Lập tức hồi sinh nó!
autorestart=true
# Cho phép công nhân 10 giây để dọn dẹp biến khi bị ép dừng
stopwaitsecs=10
user=www-data
redirect_stderr=true
stdout_logfile=/var/var/www/html/storage/logs/worker.log
4. Giải mã Binh pháp chuẩn Senior
Bạn hãy chú ý vào các cấu hình sống còn trong file supervisord.conf phía trên:
- numprocs=10: Thay vì 1, bạn vừa ra lệnh triệu hồi 10 Worker chạy ngầm song song cùng một lúc. Khi có 10.000 giao dịch quẹt thẻ đổ về, 10 công nhân này sẽ lao vào chia nhau bốc Job từ trong Tube của Beanstalkd ra xử lý, tốc độ giải phóng hàng đợi tăng lên gấp 10 lần! Bạn có thể chỉnh con số này lên 20, 50 tùy vào số lượng nhân CPU của Server.
- autorestart=true: Tính năng làm nên tên tuổi của "Đội quân bất tử". Nếu một Worker xui xẻo nhận phải cái Job chứa mã thẻ bị lỗi format, code PHP ném ra Fatal Error làm sập tiến trình. Ngay trong tích tắc, Supervisor phát hiện ra và tự động gõ lệnh php artisan queue:work sinh ra một Worker mới toanh thay thế vị trí đó. Hệ thống không bao giờ bị nghẽn.
- --max-time=3600: Đòn bẩy chống Memory Leak đỉnh cao. PHP chạy vòng lặp lâu ngày sẽ bị phình RAM. Cờ này ra lệnh: "Mỗi công nhân chỉ được sống đúng 1 tiếng (3600s), làm xong tự sát". Khi công nhân tự sát, RAM được giải phóng sạch sẽ 100%. Supervisor thấy công nhân chết, lại tự động đẻ ra một công nhân mới sạch sẽ. Hệ thống của bạn có thể chạy mượt mà ròng rã suốt 5 năm không cần thợ máy can thiệp!
5. Vận hành và Cảm nhận
Chỉ cần chạy lệnh:
docker-compose build app
docker-compose up -d
Để kiểm tra uy lực của đội quân, bạn gõ lệnh chui vào container PHP và kiểm tra danh sách tiến trình:
docker exec -it afc_php_fpm bash
ps aux | grep php
Bạn sẽ nhìn thấy một cảnh tượng tuyệt đẹp: Một tiến trình supervisord chỉ huy đứng trên cùng, theo sau là tiến trình php-fpm phục vụ HTTP, và dưới cùng là 10 tiến trình queue:work đang xếp hàng thẳng tắp, liên tục rút dữ liệu từ Beanstalkd ra xử lý ầm ầm trong bóng tối.
Lời kết Series Beanstalkd & Queue
Chúng ta đã khép lại toàn bộ vòng tròn kiến trúc Hàng đợi (Queue) chuyên sâu cho Laravel:
- Bài 1: Đưa Beanstalkd vào Docker với độ an toàn dữ liệu tuyệt đối (Binlog Persistence).
- Bài 2: Làm chủ luồng sinh tử State Machine (Ready/Delayed/Buried) và thao tác sửa lỗi thực chiến với Mắt thần Console.
- Bài 3: Nâng tầm tự động hóa, giải quyết dứt điểm bài toán gián đoạn tiến trình và Memory Leak bằng quyền năng của Supervisor.
Từ bây giờ, mọi tác vụ đồng bộ đối tác Hitachi, đẩy cảnh báo hệ thống, hay chốt sổ kế toán cuối ngày của mạng lưới AFC đều sẽ chạy một cách mượt mà, trơn tru và "tàng hình" hoàn toàn sau lưng trải nghiệm quẹt thẻ siêu tốc của hành khách. Giữ vững phong độ kỹ sư lõi này nhé!
All rights reserved