Membuat produk kami siap untuk disesuaikan dengan antrian Laravel

Terjemahan artikel disiapkan khusus untuk siswa kursus "Framework Laravel" .




Hai, saya Valerio, seorang insinyur perangkat lunak dari Italia.

Panduan ini ditujukan untuk semua pengembang PHP yang sudah memiliki aplikasi online dengan pengguna sungguhan, tetapi yang tidak memiliki pemahaman yang lebih dalam tentang bagaimana menerapkan (atau secara signifikan meningkatkan) skalabilitas dalam sistem mereka menggunakan antrian Laravel. Saya pertama kali belajar tentang Laravel pada akhir 2013 di awal versi ke 5 dari framework. Kemudian saya belum menjadi pengembang yang terlibat dalam proyek-proyek serius, dan salah satu aspek kerangka kerja modern, terutama di Laravel, yang bagi saya tampaknya paling tidak bisa dipahami, adalah Antrian.

Membaca dokumentasi, saya menebak tentang potensi, tetapi tanpa pengalaman pengembangan nyata, semua ini hanya tinggal pada tingkat teori di kepala saya.
Hari ini, saya pencipta Inspector.dev- dasbor waktu nyata , yang melakukan ribuan tugas setiap jam, dan saya memahami arsitektur ini jauh lebih baik dari sebelumnya.



Dalam artikel ini saya akan memberi tahu Anda bagaimana saya menemukan antrian dan tugas dan konfigurasi apa yang membantu saya memproses sejumlah besar data secara real time, sambil menghemat sumber daya server.

pengantar


Ketika aplikasi PHP menerima permintaan http yang masuk, kode kami dijalankan secara berurutan langkah demi langkah sampai permintaan selesai dan respons dikembalikan ke klien (misalnya, browser pengguna). Perilaku sinkron ini benar-benar intuitif, dapat diprediksi, dan mudah dimengerti. Saya mengirim permintaan http ke titik akhir, aplikasi mengekstrak data dari database, mengubahnya ke format yang sesuai, melakukan beberapa tugas tambahan dan mengirimkannya kembali. Semuanya terjadi secara linear.

Tugas dan antrian memperkenalkan perilaku asinkron yang melanggar aliran garis ini. Itu sebabnya fitur-fitur ini tampak agak aneh bagi saya pada awalnya.
Tetapi kadang-kadang permintaan http yang masuk dapat memicu siklus tugas yang memakan waktu, misalnya, mengirim pemberitahuan email ke semua anggota tim. Ini mungkin berarti mengirim enam atau sepuluh email, yang mungkin memakan waktu empat atau lima detik. Oleh karena itu, setiap kali pengguna mengklik tombol yang sesuai, ia harus menunggu lima detik sebelum dapat terus menggunakan aplikasi.

Semakin banyak aplikasi tumbuh, semakin buruk masalah ini.

Apa itu tugas?


Pekerjaan adalah kelas yang mengimplementasikan metode pegangan yang berisi logika yang ingin kita jalankan secara tidak sinkron.

<?php

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Bus\Queueable;


class CallExternalAPI implements ShouldQueue
{
    use Dispatchable,
        InteractsWithQueue,
        Queueable;
        
    /**
     * @var string
     */
    protected $url;

    /**
     *    .
     *
     * @param array $Data
     */
    public function __construct($url)
    {
        $this->url = $url;
    }
    

    /**
     *  ,   .
     *
     * @return void
     * @throws \Throwable
     */
    public function handle()
    {
        file_get_contents($this->url);
    }
}

Seperti disebutkan di atas, alasan utama untuk menyimpulkan sepotong kode dalam Pekerjaan adalah untuk menyelesaikan tugas yang memakan waktu, tanpa memaksa pengguna untuk menunggu untuk menyelesaikannya.

Apa yang kita maksudkan dengan “tugas yang melelahkan”?


Ini pertanyaan alami. Mengirim email adalah contoh paling umum yang digunakan dalam artikel yang berbicara tentang antrian, tetapi saya ingin memberi tahu Anda tentang pengalaman nyata dari apa yang perlu saya lakukan.

Sebagai pemilik produk, sangat penting bagi saya untuk menyinkronkan informasi perjalanan pengguna dengan alat pemasaran dan dukungan pelanggan kami. Dengan demikian, berdasarkan tindakan pengguna, kami memperbarui informasi pengguna di berbagai perangkat lunak eksternal melalui API (atau panggilan http eksternal) untuk tujuan layanan dan pemasaran.
Salah satu titik akhir yang paling umum digunakan dalam aplikasi saya dapat mengirim 10 email dan membuat 3 panggilan http ke layanan eksternal sebelum selesai. Tidak ada pengguna yang akan menunggu begitu lama - kemungkinan besar, mereka semua berhenti menggunakan aplikasi saya.

Berkat antriannya, saya dapat merangkum semua tugas ini di kelas yang dialokasikan, mentransfer informasi yang diperlukan untuk pelaksanaan pekerjaan mereka ke konstruktor, dan menjadwalkannya untuk diselesaikan di kemudian hari di latar belakang sehingga pengontrol saya dapat segera mengembalikan jawabannya.

<?php

class ProjectController 
{
    public function store(Request $request)
    {
        $project = Project::create($request->all());
        
        //  NotifyMembers, TagUserActive, NotifyToProveSource 
        //   ,     
        Notification::queue(new NotifyMembers($project->owners));
        $this->dispatch(new TagUserAsActive($project->owners));
        $this->dispatch(new NotifyToProveSource($project->owners));
        
        return $project;
    }
}

Saya tidak perlu menunggu selesainya semua proses ini sebelum mengembalikan jawabannya; sebaliknya, penantian akan sama dengan waktu yang dibutuhkan untuk mempublikasikannya dalam antrian. Dan itu berarti perbedaan antara 10 detik dan 10 milidetik !!!

Siapa yang melakukan tugas ini setelah mengirimnya ke antrian?


Ini adalah arsitektur penerbit / konsumen klasik . Kami telah menerbitkan tugas-tugas kami dalam antrian dari controller, sekarang kami akan memahami bagaimana antrian digunakan, dan, akhirnya, tugas-tugas dilakukan.



Untuk menggunakan antrian, kita perlu menjalankan salah satu perintah artisan paling populer:

php artisan queue:work

Seperti yang dikatakan dalam dokumentasi:
Laravel menyertakan pekerja antrian yang memproses tugas baru ketika mereka sedang antri.

Bagus! Laravel menyediakan antarmuka yang sudah jadi untuk tugas antrian dan perintah yang siap digunakan untuk mengambil tugas dari antrian dan menjalankan kode mereka di latar belakang.

Peran Pengawas


Itu adalah "hal aneh" di awal. Saya pikir itu normal untuk menemukan hal-hal baru. Setelah tahap pelatihan ini, saya menulis artikel ini untuk membantu saya mengatur keterampilan saya, dan pada saat yang sama membantu pengembang lain memperluas pengetahuan mereka.

Jika tugas gagal saat melempar pengecualian, tim akan queue:workmenghentikan pekerjaannya.

Agar proses queue:workberjalan terus menerus (menghabiskan antrian Anda), Anda harus menggunakan monitor proses seperti Supervisor untuk memastikan bahwa perintah queue:worktidak berhenti bekerja bahkan jika tugas melempar pengecualian. Supervisor memulai kembali perintah setelah crash, mulai lagi dari tugas berikutnya, mengesampingkan pengecualian melempar.

Tugas akan berjalan di latar belakang di server Anda, tidak lagi tergantung pada permintaan HTTP. Ini memperkenalkan beberapa perubahan yang harus saya pertimbangkan ketika mengimplementasikan kode tugas.

Berikut adalah yang paling penting yang akan saya perhatikan:

Bagaimana saya mengetahui bahwa kode tugas tidak berfungsi?


Saat berjalan di latar belakang, Anda tidak dapat segera melihat bahwa tugas Anda menyebabkan kesalahan.
Anda tidak akan lagi memiliki umpan balik langsung, seperti ketika membuat permintaan http dari browser Anda. Jika tugas gagal, ia akan melakukannya diam-diam dan tidak ada yang akan memperhatikan.

Pertimbangkan untuk mengintegrasikan alat pemantauan waktu nyata seperti Inspektur ke permukaan setiap kekurangan.

Anda tidak memiliki permintaan http


Tidak ada lagi permintaan HTTP. Kode Anda akan dieksekusi dari cli.

Jika Anda membutuhkan parameter kueri untuk menyelesaikan tugas Anda, Anda harus meneruskannya ke konstruktor tugas untuk digunakan nanti saat runtime:

<?php

//   

class TagUserJob implements ShouldQueue
{
    public $data;
    
    public function __construct(array $data)
    {
        $this->data = $data;
    }
}

//       

$this->dispatch(new TagUserJob($request->all()));

Anda tidak tahu siapa yang masuk


Tidak ada lagi sesi . Dengan cara yang sama, Anda tidak akan tahu identitas pengguna yang masuk, jadi jika Anda membutuhkan informasi tentang pengguna untuk menyelesaikan tugas, Anda harus meneruskan objek pengguna ke konstruktor tugas:

<?php

//   
class TagUserJob implements ShouldQueue
{
    public $user;
    
    public function __construct(User $user)
    {
        $this->user= $user;
    }
}

//       
$this->dispatch(new TagUserJob($request->user()));

Memahami bagaimana skala


Sayangnya, dalam banyak kasus ini tidak cukup. Menggunakan satu baris dan konsumen mungkin segera menjadi tidak berguna.

Antrian adalah buffer FIFO ("masuk pertama, keluar pertama"). Jika Anda telah merencanakan banyak tugas, mungkin bahkan dari jenis yang berbeda, mereka perlu menunggu orang lain untuk menyelesaikan tugas mereka sebelum menyelesaikan.

Ada dua cara untuk menskalakan:

Beberapa konsumen per antrian



, jadi, lima tugas akan dihapus dari antrian sekaligus, mempercepat pemrosesan antrian.

Antrian Tujuan Khusus

Anda juga dapat membuat antrian khusus untuk setiap jenis tugas yang akan diluncurkan dengan konsumen khusus untuk setiap antrian.



Dengan demikian, setiap antrian akan diproses secara mandiri, tanpa menunggu jenis tugas lainnya selesai.

Cakrawala


Laravel Horizon adalah manajer antrian yang memberi Anda kendali penuh atas berapa banyak antrian yang ingin Anda atur, dan kemampuan untuk mengatur konsumen, memungkinkan pengembang untuk menggabungkan kedua strategi ini dan mengimplementasikan yang sesuai dengan kebutuhan skalabilitas Anda.

Peluncuran terjadi melalui horizon artisan php alih-alih antrian artisan php: work . Perintah ini memindai file konfigurasi Anda horizon.phpdan memulai serangkaian pekerja antrian tergantung pada konfigurasi:

<?php

'production' => [
    'supervisor-1' => [
        'connection' => "redis",
        'queue' => ['adveritisement', 'logs', 'phones'],
        'processes' => 9,
        'tries' => 3,
        'balance' => 'simple', //   simple, auto  null

    ]
]

Pada contoh di atas, Horizon akan memulai tiga antrian dengan tiga proses yang ditugaskan untuk memproses setiap antrian. Seperti disebutkan dalam dokumentasi Laravel, pendekatan berbasis kode Horizon memungkinkan konfigurasi saya untuk tetap berada dalam sistem kontrol versi di mana tim saya dapat berkolaborasi. Ini adalah solusi sempurna menggunakan alat CI.

Untuk mengetahui arti parameter konfigurasi secara rinci, baca artikel yang luar biasa ini .

Konfigurasi saya sendiri



<?php

'production' => [
    'supervisor-1' => [
        'connection' => 'redis',
        'queue' => ['default', 'ingest', 'notifications'],
        'balance' => 'auto',
        'processes' => 15,
        'tries' => 3,
    ],
]

Inspektur terutama menggunakan tiga antrian:

  • menelan proses untuk menganalisis data dari aplikasi eksternal;
  • pemberitahuan digunakan untuk segera menjadwalkan pemberitahuan jika kesalahan terdeteksi saat menerima data;
  • default digunakan untuk tugas-tugas lain yang saya tidak ingin campur dengan proses menelan dan pemberitahuan .

Melalui penggunaan balance=autoHorizon, ia memahami bahwa jumlah maksimum proses yang diaktifkan adalah 15, yang akan didistribusikan secara dinamis tergantung pada pemuatan antrian.

Jika antrian kosong, Horizon mendukung satu proses aktif untuk setiap antrian, yang memungkinkan konsumen untuk segera memproses antrian jika tugas dijadwalkan.

Pengamatan penutup


Eksekusi latar belakang bersamaan dapat menyebabkan banyak kesalahan tak terduga lainnya, seperti MySQL "Lock time out" dan banyak masalah desain lainnya. Baca lebih lanjut di sini .

Saya harap artikel ini membantu Anda menggunakan antrian dan tugas dengan lebih percaya diri. Jika Anda ingin tahu lebih banyak tentang kami, kunjungi situs web kami di www.inspector.dev

Sebelumnya diterbitkan di sini www.inspector.dev/what-worked-for-me-using-laravel-queues-from-the-basics-to -cakrawala



Dapatkan kursus dan dapatkan diskon.



All Articles