跳到主要内容

เนื้อหาภาษาไทย / 泰语内容

系统指南 内容已审核

การใช้ Queues สำหรับ Background Processing

บทความนี้แนะนำการใช้ Queues สำหรับ Background Processing เพื่อปรับปรุงประสิทธิภาพและความเสถียรของ API โดยเฉพาะอย่างยิ่งกับ Task ที่ใช้เวลานาน ซึ่งจะช่วยให้ API...

การใช้ Queues สำหรับ Background Processing

ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการทำ Rate Limiting เพื่อควบคุมปริมาณ Request ที่เข้ามายัง API ของเรา ในบทนี้ เราจะมาเรียนรู้เกี่ยวกับการใช้ Queues สำหรับ Background Processing ซึ่งเป็นอีกหนึ่งเทคนิคสำคัญในการปรับปรุงประสิทธิภาพและความเสถียรของ API โดยเฉพาะอย่างยิ่งเมื่อต้องจัดการกับ Task ที่ใช้เวลานาน

Queues คืออะไร?

Queues หรือ คิว คือ โครงสร้างข้อมูลที่ทำงานแบบ FIFO (First-In, First-Out) ซึ่งหมายความว่าข้อมูลที่ถูกเพิ่มเข้าไปในคิวเป็นลำดับแรก จะถูกนำออกมาประมวลผลก่อนเสมอ ในบริบทของ API และ Web Services, Queues ถูกนำมาใช้เพื่อจัดการกับ Task ที่ไม่จำเป็นต้องประมวลผลทันที (Asynchronous Processing) เช่น การส่งอีเมล, การประมวลผลรูปภาพ, การ Generate PDF Reports หรือการเรียกใช้งาน External API อื่นๆ

ทำไมต้องใช้ Queues?

  • ปรับปรุง Response Time: เมื่อ API ได้รับ Request ที่ต้องประมวลผล Task ที่ใช้เวลานาน การส่ง Task นั้นไปยัง Queue จะช่วยให้ API สามารถตอบกลับ Client ได้ทันที โดยไม่ต้องรอให้ Task นั้นเสร็จสิ้น
  • เพิ่มความเสถียรของระบบ: หากมี Task ที่ใช้เวลานานจำนวนมากเข้ามาพร้อมกัน อาจทำให้ API Overload และล่มได้ การใช้ Queue จะช่วยกระจาย Load ทำให้ระบบมีความเสถียรมากขึ้น
  • Resilience: หาก Worker ที่ประมวลผล Task ใน Queue เกิดปัญหา (เช่น ล่ม) Task นั้นจะยังคงอยู่ใน Queue และสามารถถูกประมวลผลใหม่ได้เมื่อ Worker กลับมาทำงาน
  • Scalability: การใช้ Queue ช่วยให้เราสามารถ Scale Worker ที่ประมวลผล Task ได้อย่างอิสระ โดยไม่กระทบต่อ API หลัก

การใช้งาน Queues

การใช้งาน Queues โดยทั่วไปประกอบด้วย 3 ส่วนหลัก:

  1. Producer: คือส่วนที่สร้าง Task และเพิ่ม Task นั้นเข้าไปใน Queue (Enqueuing). ในบริบทของ API, Producer มักจะเป็น Controller ที่รับ Request จาก Client และตัดสินใจว่าจะส่ง Task ใดไปประมวลผลใน Background
  2. Queue: คือตัวกลางที่เก็บ Task ที่ยังไม่ได้ถูกประมวลผล
  3. Consumer (Worker): คือส่วนที่ดึง Task ออกจาก Queue (Dequeuing) และประมวลผล Task นั้น

ตัวอย่างการใช้งาน:

สมมติว่าเรามี API สำหรับ Upload รูปภาพ เมื่อ Client Upload รูปภาพเข้ามา เราต้องการ:

  1. บันทึกรูปภาพลงใน Storage
  2. สร้าง Thumbnail ของรูปภาพ
  3. ส่ง Notification อีเมลให้ User

การสร้าง Thumbnail และการส่ง Notification อีเมล เป็น Task ที่ใช้เวลาพอสมควร เราจึงควรส่ง Task เหล่านี้ไปประมวลผลใน Background โดยใช้ Queues

Producer (Controller):

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Jobs\GenerateThumbnail;
use App\Jobs\SendNotificationEmail;

class ImageController extends Controller
{
    public function upload(Request $request)
    {
        // Validate the request
        $request->validate([
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
        ]);

        // Save the image to storage
        $image = $request->file('image');
        $imageName = time().'.'.$image->getClientOriginalExtension();
        $image->storeAs('images', $imageName);

        // Dispatch the jobs to the queue
        GenerateThumbnail::dispatch($imageName);
        SendNotificationEmail::dispatch($request->user()->email, $imageName);

        return response()->json(['message' => 'Image uploaded successfully. Processing in background.'], 200);
    }
}

ในตัวอย่างนี้ เราใช้ Laravel Queue System โดยใช้ dispatch() method เพื่อส่ง Jobs GenerateThumbnail และ SendNotificationEmail ไปยัง Queue

Consumer (Worker):

Consumer คือ Process ที่ทำงานอยู่เบื้องหลัง และรอรับ Task จาก Queue เมื่อมี Task ใหม่เข้ามา Consumer จะดึง Task นั้นออกมา และประมวลผล

GenerateThumbnail Job:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Intervention\Image\Facades\Image;

class GenerateThumbnail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $imageName;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($imageName)
    {
        $this->imageName = $imageName;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $imagePath = storage_path('app/images/' . $this->imageName);
        $thumbnailPath = storage_path('app/thumbnails/' . $this->imageName);

        // Create thumbnail
        $img = Image::make($imagePath)->resize(200, 200);
        $img->save($thumbnailPath);

        // Log that thumbnail was created
        \Log::info('Thumbnail created for image: ' . $this->imageName);
    }
}

SendNotificationEmail Job:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;

class SendNotificationEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $email;
    protected $imageName;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($email, $imageName)
    {
        $this->email = $email;
        $this->imageName = $imageName;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // Send email
        Mail::raw('Your image ' . $this->imageName . ' has been uploaded and processed.', function ($message) {
            $message->to($this->email)->subject('Image Uploaded');
        });

        // Log that email was sent
        \Log::info('Notification email sent to: ' . $this->email . ' for image: ' . $this->imageName);
    }
}

ในตัวอย่างนี้ เราใช้ Laravel Jobs ซึ่งเป็น Class ที่ Implement Interface ShouldQueue ซึ่งบอกให้ Laravel Queue System รู้ว่า Class นี้เป็น Task ที่ควรถูกประมวลผลใน Background handle() method คือส่วนที่กำหนด Logic ในการประมวลผล Task

การตั้งค่า Queues

ในการใช้งาน Queues เราต้องมีการตั้งค่า Queue Connection ก่อน Laravel รองรับ Queue Connection หลายประเภท เช่น:

  • sync: ประมวลผล Task ทันที (สำหรับ Development)
  • database: ใช้ Database เป็น Queue
  • redis: ใช้ Redis เป็น Queue (แนะนำสำหรับ Production)
  • beanstalkd: ใช้ Beanstalkd เป็น Queue
  • sqs: ใช้ Amazon SQS เป็น Queue

การตั้งค่า Queue Connection ใน Laravel:

แก้ไขไฟล์ .env และกำหนดค่า QUEUE_CONNECTION:

QUEUE_CONNECTION=redis

จากนั้นแก้ไขไฟล์ config/queue.php เพื่อกำหนดค่า Connection ที่ต้องการ:

<?php

return [

    'default' => env('QUEUE_CONNECTION', 'sync'),

    'connections' => [

        'sync' => [
            'driver' => 'sync',
        ],

        'database' => [
            'driver' => 'database',
            'table' => 'jobs',
            'queue' => 'default',
            'retry_after' => 90,
        ],

        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => env('REDIS_QUEUE', 'default'),
            'retry_after' => 90,
            'block_for' => null,
        ],

    ],

    'failed' => [
        'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
        'database' => env('DB_CONNECTION', 'mysql'),
        'table' => 'failed_jobs',
    ],

];

การรัน Worker:

เมื่อตั้งค่า Queue Connection เรียบร้อยแล้ว เราสามารถรัน Worker ได้โดยใช้ Artisan Command:

php artisan queue:work

หรือหากต้องการรัน Worker แบบ Daemon (ทำงานอยู่เบื้องหลังตลอดเวลา):

php artisan queue:work --daemon

ข้อควรระวัง:

  • ตรวจสอบให้แน่ใจว่า Server มี Resources เพียงพอสำหรับการรัน Worker
  • Monitoring Queue Length เพื่อตรวจสอบว่ามี Task ค้างอยู่ใน Queue มากเกินไปหรือไม่
  • จัดการ Error ใน Jobs อย่างเหมาะสม เพื่อป้องกันไม่ให้ Jobs ล้มเหลวและทำให้ Queue เต็ม

การใช้ Queues สำหรับ Background Processing เป็นเทคนิคที่มีประโยชน์อย่างมากในการปรับปรุงประสิทธิภาพและความเสถียรของ API โดยเฉพาะอย่างยิ่งเมื่อต้องจัดการกับ Task ที่ใช้เวลานาน การเลือก Queue Connection ที่เหมาะสม และการ Monitoring Queue อย่างสม่ำเสมอ จะช่วยให้ API ของคุณทำงานได้อย่างราบรื่นและมีประสิทธิภาพ

ในบทถัดไป เราจะมาเรียนรู้เกี่ยวกับการ Implement Caching เพื่อเพิ่มความเร็วในการตอบสนองของ API

Office.in.th Custom Service

想基于此结构开发或定制系统?

Office.in.th 承接企业级 Web Application、API Integration 以及政府/企业管理系统的设计与开发,并提供长期支持。

查看软件开发服务