Laravel'de kuyruk (queue) kullanımı

Merhabalar,

Bu yazıda Laravel'de kuyruk (queue) kullanımından bahsedeceğim. Senaryomuz şu şekilde olacak. Kullanıcının bilgilerini alıp MERNIS kontrolünden geçiren ve bilgilerin doğruluğuna yönelik kullanıcıya e-posta gönderen ufak bir API fonksiyonu yazacağız. Böylece kullanıcı MERNIS kontrolünün tamamlanması ve e-posta gönderilmesi işlemlerinin bitmesini beklemeden cevabı direkt görmüş olacak. Örnek projeyi Github üzerinden paylaştım. Oradan da indirip inceleyebilirsiniz.

Örnek Proje Linki

İlk olarak komut satırında masaüstü dizinine gelerek aşağıdaki komutu yazıp yeni bir Laravel projesi oluşturuyorum:

composer create-project --prefer-dist laravel/laravel queue

Sonrasında Xampp yardımıyla yerelde bir veritabanı oluşturuyorum. Proje kök dizinindeki .env dosyasını açarak veritabanı bilgilerini aşağıdaki gibi düzenliyorum:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=queue
DB_USERNAME=root
DB_PASSWORD=

defaultStringLength hatasıyla karşılaşmamak için app/Providers/AppServiceProvider.php dosyasını açarak boot() fonksiyonunu düzenliyorum:

public function boot()
{
    Schema::defaultStringLength(191);
}

Şimdi kuyrukta yapılacak işlem için bir job oluşturuyorum.

php artisan make:job SendMernis

Gelen isteği karşılayacak olan fonksiyonum için bir controller oluşturuyorum.

php artisan make:controller UserController

api.php dosyasında istek için route belirtiyorum.

Route::post('register', '[email protected]');

register fonksiyonum tam olarak şu şekilde olacak:

public function register()
{
    $user['name'] = request()->name;
    $user['surname'] = request()->surname;
    $user['birth_year'] = request()->birth_year;
    $user['nationality_id'] = request()->nationality_id;
    $user['email'] = request()->email;
    $this->dispatch(new SendMernis($user));
    return response()->json([
        'message' => 'Bilgileriniz Mernis kontrolünden geçirilerek tarafınıza e-posta gönderilecektir.'
    ], 200);
}

Bu fonksiyonda kullanıcıdan gelen ad, soyad, doğum yılı, TC kimlik numarası ve e-posta adresi bilgilerini kuyruktaki fonksiyonumuza gönderdik ve kullanıcıya direkt olarak bir mesaj döndük.

resources/views klasörü içerisinde email adında bir klasör açıyorum. mernis_control adında bir blade dosyası açarak içeriğini şu şekilde dolduruyorum.

<html>
<head>
  <meta charset="utf-8">
  <title>Mernis Kontrolü</title>
</head>
<body>
  <div>
    {{ $content }}
  </div>
</body>
</html>

SendMernis.php dosyasında kuyruğa gelen işlemi karşılayan kısım olan handle ı şu şekilde dolduruyoruz:

public function handle()
{
  $informations = array(
    "name" => $this->user['name'],
    "surname" => $this->user['surname'],
    "birth_year" => $this->user['birth_year'],
    "nationality_id" => $this->user['nationality_id']
  );
  $response = $this->mernis_control($informations);
  $content = $response == "true" ? 'Bilgileriniz doğru.' : 'Bilgileriniz yanlış.';
  $data = array(
    'content' => $content
  );
  $this->send_mail('email.mernis_control', $data, $this->user['email'], 'Mernis Kontrolü');
}

mernis_control fonksiyonumuz şu şekilde:

public function mernis_control($informations)
{
  $send = '<?xml version="1.0" encoding="utf-8"?>
     <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
          <soap:Body>
            <TCKimlikNoDogrula xmlns="http://tckimlik.nvi.gov.tr/WS">
              <TCKimlikNo>'.$informations["nationality_id"].'</TCKimlikNo>
              <Ad>'.$informations["name"].'</Ad>
              <Soyad>'.$informations["surname"].'</Soyad>
              <DogumYili>'.$informations["birth_year"].'</DogumYili>
            </TCKimlikNoDogrula>
          </soap:Body>
     </soap:Envelope>';
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL,      "https://tckimlik.nvi.gov.tr/Service/KPSPublic.asmx");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST,     true);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_HEADER,    false);
  curl_setopt($ch, CURLOPT_POSTFIELDS,  $send);
  curl_setopt($ch, CURLOPT_HTTPHEADER,  array(
    'POST /Service/KPSPublic.asmx HTTP/1.1',
    'Host: tckimlik.nvi.gov.tr',
    'Content-Type: text/xml; charset=utf-8',
    'SOAPAction: "http://tckimlik.nvi.gov.tr/WS/TCKimlikNoDogrula"',
    'Content-Length: '.strlen($send)
  ));
  $response = curl_exec($ch);
  curl_close($ch);
  return strip_tags($response);
}

send_mail fonksiyonumuz şu şekilde:

public function send_mail($template, $data, $to, $subject)
{
  Mail::send($template, $data, function ($message) use ($to, $subject) {
    $message->to($to)->subject($subject);
  });
}

Şimdi kuyruk işlemlerini veritabanında tutan jobs tablosunu oluşturmak için şu komutu yazıyoruz:

php artisan queue:table

Kuyruk işlemlerinin veritabanındaki tablodan işlenmesi için .env dosyasında şöyle bir düzenleme yapıyoruz:

QUEUE_DRIVER=database

Şimdi de veritabanı tablolarını oluşturmak için şu komutu yazıyoruz:

php artisan migrate

.env dosyasında mail ayarlarını düzenliyoruz:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=f901938115ba94
MAIL_PASSWORD=4e8d739fbd82a1
MAIL_ENCRYPTION=null

Artık herşey hazır olduğuna göre projemizi çalıştırıp sonuca ulaşalım:

php artisan serve
php artisan queue:work (kuyruktaki işlemleri dinlemek için)

Postman'i açıp http://localhost:8000/api/register linkine aşağıdaki şekilde gerekli bilgilerle POST isteği yapıyoruz ve sonucu görüyoruz.

Evet yerel ortamda herşey gayet güzel çalışıyor. Ancak projemizi sunucuya attığımız zaman php artisan queue:work komutunun sürekli çalışıyor olması gerekecek. Bunun içinde supervisor paketini kullanacağız. Eğer sunucumuda supervisor yoksa şu komutu yazarak yüklüyoruz:

sudo apt-get install supervisor

Sonrasında /etc dizinindeki supervisord.conf dosyasını vim ile açıyoruz:

sudo vim /etc/supervisord.conf

Ve içeriğine şu satırları ekliyoruz:

[program:laravel-worker]
command=/usr/bin/php /var/www/vhosts/queue/artisan queue:work --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)02d
numprocs=8
priority=999
autostart=true
autorestart=true
startsecs=0
startretries=3
user=apache
redirect_stderr=true
stdout_logfile=/var/www/vhosts/queue/storage/logs/worker.log

Supervisor servisini başlatarak işlemi bitiriyoruz:

service supervisord start

Umarım yararlı olmuştur. 

İyi çalışmalar.

Yusuf Borucu

Benim adım Yusuf. 1993 yılında Şanlıurfa'da doğdum. 2015 yılında Bilecik Şeyh Edebali Üniversitesi'nde Bilgisayar Mühendisliği bölümünden mezun oldum. Şu anda özel bir şirkette Yazılım Geliştirici olarak çalışmaktayım. Yazılıma yönelik uğraştığım, sevdiğim ve ilgi duyduğum teknolojilerden bahsetmem gerekirse; Laravel, MySQL (mevcut çalıştığım şirkette uğraştıklarım). Asp.Net Mvc, MSSQL (önceden ça...

"Laravel'de kuyruk (queue) kullanımı" için 2 yorum yapıldı.
S.H
salih hanifeoğlu 29 Eylül 2019

merhaba öncelikle güzel bir konu işlemişsiniz teşekkür ederim, benim anlamadığım konu queue:work diyerek eklediğimiz notification lar otomatik olarak job table ne varsa atıyor bunu göndermek için illaki 3th party birseymi eklemek lazım queue:work muadili supervisor paketitni kullanmamız sart mı 5.8 veya 6 da teşekkür ederim umarım sorumu sorabilmisimdir. :)

Yusuf Borucu (Yazı sahibi)25 Ekim 2019

Merhaba, sorunuza ancak dönüş yapabiliyorum kusura bakmayın. Şöyle ki; eğer sunucuya ssh ile erişip projenin dizinine gelerek queue:work komutunu çalıştırırsak aslında olay bitmiş olur. 7/24 ssh erişimi sağlanmış şekilde kalacak bir bilgisayar varsa sorun olmaz yani. Ancak ssh erişimini sonlandırdığımız zaman o komutu çalıştırmayı da sonlandırmış oluruz. Oysa ki queue:work komutunun o dizinde sürekli olarak çalışması gerekiyor. Bunu da bize şuan için 3th party paketler sağlıyor ki o konuda da supervisor oldukça başarılı. İlerleyen zamanlarda farklı bir çözüm olursa onu da yazıya ekleyeceğim. İyi çalışmalar.

Yorum yap * E-posta adresiniz yayınlanmayacak.