İçeriğe geç
Can Uğurlu
Geri dön

Queue worker'ı Supervisor ile çalıştırın

Terminalde php artisan queue:work çalıştırmak bir dağıtım değil. Terminal kapanınca, sunucu yeniden başlayınca ya da worker bir hata alınca süreç ölür ve onu kimse yeniden başlatmaz.

Worker’ı canlıya çıkarmanın doğru yolu bir süreç yöneticisiyle çalıştırmak. Bu yazıda Supervisor.

Worker neden ölür

Bunların hiçbiri istisna değil, günlük işleyişin parçası. Sistem bunu varsayarak kurulmalı.

Supervisor konfigürasyonu

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/storage/logs/worker.log
stopwaitsecs=3600

numprocs=4 dört paralel worker süreci başlatır. Kuyruk hacmi arttıkça bu sayı artırılır, tek başına iş kaybını önlemez ama işlem hızını artırır.

autorestart=true bu konfigürasyonun asıl işi. Süreç herhangi bir sebeple ölürse Supervisor onu anında yeniden başlatır. Terminalde çalıştırılan bir queue:work’te bu yok, süreç ölür, kuyruk birikir, kimse fark etmez.

stopwaitsecs=3600 Supervisor’a süreci durdururken en fazla ne kadar bekleyeceğini söylüyor. Worker o an bir iş işliyorsa, işi yarıda kesmek yerine bitmesine izin veriliyor. Bu değer en uzun işinizin süresinden büyük olmalı, yoksa Supervisor işi zorla keser.

queue:work neden queue:listen’dan daha doğru

queue:listen her iş için framework’ü baştan başlatır (bootstrap eder). queue:work framework’ü bir kere yükler, sonra sürekli çalışır. Bu fark prodüksiyonda gözle görülür bir performans farkına dönüşüyor, çünkü listen her işte tüm service provider’ları yeniden çalıştırıyor.

listen’ın tek avantajı kod değişikliğini anında yansıtması. work eski kodu bellekte tutmaya devam ediyor. Bu ödünleşim bir sonraki başlıkta.

Worker eski kodu bellekte tutar

queue:work başladığı andaki kod sürümünü hafızada tutuyor. Deploy sırasında dosyalar değişse bile worker süreci yeniden başlamadan yeni kodu görmüyor. Bu, deploy’dan sonra worker’ın hâlâ eski davranışı sergilediği ve kimsenin sebebini anlamadığı durumların birebir sebebi.

Çözüm deploy script’ine queue:restart eklemek:

php artisan queue:restart

Bu komut worker’ı hemen durdurmuyor. O an işlenen işin bitmesini bekliyor, sonra süreç kapanıyor. Supervisor autorestart=true sayesinde süreci anında yeniden başlatıyor, bu sefer güncel kodla.

--max-time ve --max-jobs bellek sızıntısına karşı

php artisan queue:work --max-time=3600 --max-jobs=1000

--max-time=3600 worker’ı bir saatte bir kendiliğinden kapatıyor. --max-jobs=1000 bin iş işledikten sonra aynısını yapıyor. İkisi de Supervisor’ın autorestart ayarıyla birleşince, worker düzenli aralıklarla temiz bir süreçle yeniden başlıyor.

Bu, uzun süre açık kalan bir PHP sürecinin yavaş yavaş bellek biriktirmesine (bağlantı havuzları, statik referanslar, üçüncü parti kütüphanelerdeki sızıntılar) karşı bir önlem. Sızıntının kaynağını bulmak yerine süreci periyodik olarak sıfırlamak, prodüksiyonda daha ucuz bir çözüm.

Alternatif: systemd

Supervisor yerine systemd de aynı işi görür, özellikle sunucuda zaten systemd varsa ek bir paket kurmadan çalışır:

[Unit]
Description=Laravel queue worker
After=network.target

[Service]
User=www-data
Restart=always
ExecStart=/usr/bin/php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600

[Install]
WantedBy=multi-user.target

Restart=always Supervisor’daki autorestart=true ile aynı görevi görüyor. Seçim genelde altyapıya bağlı: Docker container’da genelde Supervisor tercih edilir çünkü aynı container içinde birden fazla süreci yönetebiliyor, çıplak bir VPS’te systemd zaten hazır olduğu için ek bağımlılık istemiyor.

Özet

Worker’ı terminalde değil, Supervisor ya da systemd altında çalıştırın. autorestart açık olsun. Deploy script’ine queue:restart ekleyin. --max-time ve --max-jobs ile süreci periyodik olarak sıfırlayın.


Bu yazıyı paylaş:

Önceki Yazı
Liquid'de döngü maliyeti
Sonraki Yazı
Tarihi UTC sakla, gösterimde çevir