آشنایی با مفاهیم Queue و Job در لاراول
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 6 دقیقه

آشنایی با مفاهیم Queue و Job در لاراول

صف‌ها (Queue) یکی از مفاهیم پیچیده در دنیا برنامه نویسی است که پیاده‌سازی نسبتا چالش‌ برانگیزی داشته و به همین دلیل تنها برنامه نویسان حرفه‌ای سراغ آن می‌روند. کاربردها و سناریوهای مختلفی نیز وجود دارد که تنها با به کارگیری صف‌ها توانایی پیاده‌سازی آن‌ها را خواهید داشت. 

به همین دلیل در این مطلب قصد داریم شما را با مفهوم صف در لاراول و نحوه پیاده‌سازی آن آشنا کنیم و با ضرورت آن آشنا شویم. از طرفی دیگر، اگر قصد دارید که به صورت کامل با مفهوم و کاربرد Queue آشنا شوید به شما پیشنهاد می‌کنم که دوره آموزشی «آموزش پیشرفته صف‌ها در لاراول» را مشاهده کنید.

اولین باری که از لاراول استفاده کردم، مربوط به نسخه ۵ آن می‌شود. در آن زمان توسعه دهنده چندان حرفه‌ای به حساب نمی‌آمدم و به همین دلیل با یادگیری مفاهیم پیچیده‌تر سعی کردم تا سطح دانش خود را افزایش دهم. به همین دلیل تصمیم گرفتم تا از مفهوم «صف یا Queue» شروع کنم. 

در این مقاله قصد دارم به شما نشان دهم که چگونه queueها و jobها را کشف کردم و چه ویژگی‌هایی از این تکنولوژی‌ها به من کمک کردند تا ضمن حفظ منابع سرور به صورت مقرون به صرفه، مقدار زیادی از داده‌ها را به صورت بلادرنگ یا Real Time نگهداری و پردازش کنم.

مقدمه

روش کلی اجرای اپلیکیشن‌های سمت سرور به این شکل است که پاسخ درخواست‌های کاربران را به صورت مرحله به مرحله و در یک نوبت خطی ارائه می‌دهد. این موضوع مشکلات و چالش‌های مختلفی را بوجود می‌آورد. برای مثال تصور کنید که کاربر اول شما به یک دقیقه زمان برای پردازش درخواست‌ش نیاز دارد، در صورتی که کاربر دوم، سوم و چهارم هر کدام به ده ثانیه زمان نیاز دارند. این کاربران باید ابتدا منتظر تمام شدن کاربر اول باشند سپس به صورت ترتیبی به درخواست‌ها آن‌ها پاسخ داده شود. این حالت ابدا بهینه نبوده و منجر به کاهش بهره‌وری وبسایت می‌شود.

در این حالت تکنولوژی Queue و Job به کمک ما آمده و این جریان خطی پاسخ به کاربران را از بین می‌برند و در نهایت باعث می‌شوند تا به صورت ناهمزمان همه کارها پیش برود. در ادامه به صورت کامل‌تر با هر دو این تکنولوژی‌ها آشنا می‌شویم و قطعه کدهایی از هر کدام‌شان را در زبان PHP و فریمورک Laravel مشاهده خواهیم کرد.

Job چیست؟

Job یک کلاس است که متد "handle" را اجرا می‌کند. این کلاس شامل منطقی است که به ما کمک می‌کند تا درخواست‌ها را به صورت موازی و در کنار همدیگر اجرا کنیم. 

<?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;

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

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

این تکه کد باعث می‌شود تا Job فعال شود و کارهای وقت‌گیر را بدون انتظار کشیدن کاربران دیگر اجرا کند. 

منظور از "کارهای وقت‌گیر" چیست؟

ارسال ایمیل‌ یکی از کارهای وقت‌گیری است که توان پردازشی و زمان زیادی را برای به انجام رساندن صرف می‌کند. این یکی از مثال‌های همیشگی است که بسیاری از افراد از آن استفاده می‌کنند. 

اما به عنوان یک صاحب محصول، این مهم است که اطلاعات کاربران را با ابزارهای بازاریابی و پشتیبانی مشتری همگام کنیم. بنابراین بر اساس اقدامات کاربر، ما اطلاعات را به نرم‌افزارهای مختلف خارجی از طریق API برای اهداف بازاریابی و مراقبت از مشتری بروزرسانی می‌کنیم.

یکی از مهم‌ترین موارد استفاده شده در برنامه ما این است که می‌تواند 10 ایمیل را ارسال کند و 3 فراخوانی http را برای انجام خدمات خارجی انجام دهد. هیچ کاربر منتظر این همه مدت نیست، به احتمال زیاد آن‌ها از استفاده از این برنامه منصرف می‌شوند.

با تشکر از queue، می‌توانم تمام این کارها را در کلاس‌های اختصاصی جمع‌بندی کنم، اطلاعات مربوط به انجام کار خود را در مخزن منتقل کنم و زمان اجرای آن‌ها را برای پس‌زمینه تنظیم کنم تا کنترل کننده من بتواند بلافاصله پاسخی را برگرداند.

<?php

class ProjectController 
{
    public function store(Request $request)
    {
        $project = Project::create($request->all());
        
        // Defer NotifyMembers, TagUserActive, NotifyToProveSource 
        // passing the information needed to do their job
        Notification::queue(new NotifyMembers($project->owners));
        $this->dispatch(new TagUserAsActive($project->owners));
        $this->dispatch(new NotifyToProveSource($project->owners));
        
        return $project;
    }
}

لازم نیست صبر کنید تا تمام این مراحل قبل از بازگشت پاسخ تمام شود. بلکه فقط به مدت زمانی که برای انتشار در queue منتظر خواهیم ماند نیاز داریم. این می‌تواند به معنای تفاوت بین 10 ثانیه و 10 میلی ثانیه باشد!

چه کسی این کارها را بعد از ارسال در صف انجام می‌دهد؟

این یک معماری کلاسیک "تولید کننده / مصرف کننده" است. ما به تازگی job خود را در queue از کنترلر منتشر کرده‌ایم، بنابراین اکنون قصد داریم نحوه مصرف queue و در نهایت job های اجرا شده را بفهمیم.

برای مصرف یک queue، باید یکی از محبوب‌ترین فرمان‌های artisan را اجرا کنیم:

php artisan queue:work

لاراول شامل یک کارگر صف است که به محض فشار بر روی صف، وظایف جدید را پردازش می‌کند.

همچنین لاراول یک رابط کاربری آماده برای قرار دادن وظایف در یک صف و یک دستورالعمل آماده استفاده برای بیرون کشیدن وظایف از صف و اجرای کد آنها در پس زمینه را فراهم می‌کند.

نقش supervisor

اگر یک فرایند حین اجرا شکست بخورد، صف دستور اجرای کار خود را متوقف می‌کند.

برای حفظ صف روند کار به طور دائم در حال اجرا است. باید از یک نظارت‌گر فرآیند مانند Supervisor استفاده کنید تا اطمینان حاصل شود که فرمان queue: work حتی اگر یک استثنا را از بین ببرد، متوقف نمی‌شود.

سوپروایزر بعدِ از کار افتادن فرمان، ریستارت می‌شود و کار بعدی را شروع می‌کند و فرایند دیگری را که شکست خورده است، رها می‌کند. کارها به صورت پس زمینه بر روی سرور شما اجرا می‌شوند.

اگر برای انجام وظایف خود به پارامترهای درخواستی نیاز دارید، باید آن‌ها را در کانستراکتور job منتقل کنید تا بعداً بتوانید از آن‌ها استفاده کنید:

<?php

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

// Put the job in the queue from your controller
$this->dispatch(new TagUserJob($request->all()));

شما نمی‌دانید کاربر وارد شده چه کسی است

سشن از بین رفته است. به همین دلیل شما هویت کاربری را که وارد سیستم شده را نمی‌دانید، بنابراین اگر برای انجام کار به اطلاعات کاربر نیاز دارید، باید شیء کاربر را به کانستراکتور منتقل کنید:

<?php

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

// Put the job in the queue from your controller
$this->dispatch(new TagUserJob($request->user()));

سخن پایانی

Queue و Job از جمله مهمترین تکنولوژی‌های حوزه مهندسی نرم افزار هستند و اگر کسی قصد دارد سطح دانش خود از برنامه نویسی سمت سرور را به مرحله جدیدی ببرد نیاز دارد که با این مفاهیم به خوبی آشنا شود. این مطلب صرفا یک موضوع تجربی و آزمایشی بود اما اگر قصد دارید به صورت کامل با این موارد آشنا شوید به شما پیشنهاد می‌کنم دوره آموزشی «آموزش پیشرفته صف‌ها در لاراول» را مشاهده کنید.

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
4.33 از 3 رای

/@heshmati74
عرفان حشمتی
Full-Stack Web Developer

کارشناس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

عرفان حشمتی

Full-Stack Web Developer