Kembali ke Blog
Backend

Symfony 7 + Messenger: Background Worker Hemat RAM untuk Marketplace

02 Feb 2026 Idiarsosimbang 5 menit baca
Symfony 7 + Messenger: Background Worker Hemat RAM untuk Marketplace

Worker yang stabil membuat download image, email, dan queue jalan tanpa membebani web server. Ini praktik sederhana yang relevan di 2026.


Di marketplace produk digital, banyak pekerjaan sebaiknya dilakukan secara async (asinkron): kirim email konfirmasi, proses upload gambar, generate thumbnail, update search index, hingga notifikasi ke seller. Jika semua ini dilakukan dalam satu HTTP request, user akan menunggu respons yang lama dan server akan kewalahan. Symfony Messenger hadir sebagai solusi background worker yang elegan dan hemat RAM.

Apa Itu Symfony Messenger?

Symfony Messenger adalah komponen yang memungkinkan Anda mengirim pesan (message) ke queue, lalu memproses pesan tersebut secara asinkron oleh worker process terpisah. Konsepnya mirip dengan Laravel Queue, tapi dengan arsitektur yang lebih flexible dan type-safe.

Komponen Utama

  • Message: PHP object sederhana (POPO/Plain Old PHP Object) yang berisi data yang perlu diproses
  • Message Handler: Class yang berisi logic pemrosesan message
  • Transport: Mekanisme pengiriman message (database, Redis, RabbitMQ, Amazon SQS)
  • Worker: Process yang berjalan terus-menerus, mengambil message dari queue dan menjalankan handler

Mengapa Messenger Hemat RAM?

Dibandingkan dengan alternatif seperti RabbitMQ + consumer custom, Symfony Messenger lebih hemat karena:

  • Doctrine transport: Gunakan database MySQL/PostgreSQL yang sudah ada sebagai queue. Tidak perlu install software tambahan. Untuk traffic di bawah 1000 messages/jam, ini lebih dari cukup.
  • Single worker process: Satu worker bisa menangani multiple message type. Tidak perlu menjalankan banyak consumer process.
  • Memory limit: Worker otomatis restart setelah memproses N messages atau menggunakan M MB RAM, mencegah memory leak.
  • Lazy loading: Service yang diinject ke handler hanya di-instantiate ketika handler dipanggil, bukan saat worker start.

Implementasi Step-by-Step

1. Membuat Message Class

Message adalah data object sederhana. Contoh untuk notifikasi order:


// src/Message/OrderConfirmation.php
namespace App\Message;

class OrderConfirmation
{
    public function __construct(
        private readonly int $orderId,
        private readonly string $buyerEmail,
    ) {}

    public function getOrderId(): int { return $this->orderId; }
    public function getBuyerEmail(): string { return $this->buyerEmail; }
}

2. Membuat Handler

Handler berisi logic yang akan dieksekusi saat message diproses:


// src/MessageHandler/OrderConfirmationHandler.php
namespace App\MessageHandler;

use App\Message\OrderConfirmation;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler]
class OrderConfirmationHandler
{
    public function __construct(
        private MailerInterface $mailer,
        private OrderRepository $orderRepo,
    ) {}

    public function __invoke(OrderConfirmation $message): void
    {
        $order = $this->orderRepo->find($message->getOrderId());
        // Send email, generate invoice PDF, dsb.
        $this->mailer->send(/* ... */);
    }
}

3. Konfigurasi Transport

Di config/packages/messenger.yaml:


framework:
    messenger:
        transports:
            async:
                dsn: 'doctrine://default'
                retry_strategy:
                    max_retries: 3
                    delay: 1000
                    multiplier: 2

        routing:
            App\Message\OrderConfirmation: async
            App\Message\GenerateThumbnail: async
            App\Message\UpdateSearchIndex: async

Dengan konfigurasi ini, semua message akan disimpan di tabel messenger_messages di database Anda. Tidak perlu install Redis atau RabbitMQ.

4. Dispatch Message

Di controller atau service, dispatch message ke queue:


// Di Controller
public function checkout(MessageBusInterface $bus): Response
{
    // Proses pembayaran...
    $order = $this->createOrder(/* ... */);

    // Kirim ke queue (non-blocking, return langsung)
    $bus->dispatch(new OrderConfirmation(
        $order->getId(), 
        $order->getBuyerEmail()
    ));
    $bus->dispatch(new GenerateThumbnail($order->getProduct()->getId()));

    // User langsung dapat response, email dikirim di background
    return $this->redirectToRoute('order_success');
}

5. Menjalankan Worker

Jalankan worker sebagai background process:


# Development
php bin/console messenger:consume async -vv

# Production (dengan memory limit dan time limit)
php bin/console messenger:consume async \
    --memory-limit=128M \
    --time-limit=3600 \
    --limit=500

Use Case di Marketplace

Berikut use case konkret Symfony Messenger untuk marketplace produk digital:

1. Email Transactional

  • Konfirmasi order ke buyer
  • Notifikasi penjualan ke seller
  • Reminder pembayaran (15 menit, 1 jam, 24 jam setelah checkout)
  • Review reminder (3 hari setelah download)

2. Image Processing

  • Generate thumbnail berbagai ukuran (150x150, 300x300, 600x600)
  • Compress dan optimize gambar produk (WebP conversion)
  • Watermark untuk preview gambar
  • Extract color palette untuk UI matching

3. Search Index Update

Ketika produk diupdate (harga, deskripsi, stok), jangan langsung update search index di request yang sama. Dispatch message, biarkan worker memproses re-indexing di background.

4. Analytics & Reporting

  • Track product view (untuk trending products)
  • Generate laporan penjualan harian (tiap midnight)
  • Calculate seller leaderboard

Monitoring Worker di Production

Gunakan Supervisor untuk memastikan worker selalu berjalan:


# /etc/supervisor/conf.d/messenger-worker.conf
[program:messenger-worker]
command=php /home/app/bin/console messenger:consume async --memory-limit=128M --time-limit=3600
autostart=true
autorestart=true
numprocs=2
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/messenger-worker.log

Perbandingan Transport

TransportThroughputRAMSetupCost
Doctrine (MySQL)~100 msg/sMinimal0 (sudah ada)$0
Redis~10.000 msg/s50-100MBMudah$0 (self-hosted)
RabbitMQ~50.000 msg/s200MB+Medium$10-50/mo (managed)
Amazon SQSUnlimited0 (managed)Mudah$0.40/1M requests

Untuk marketplace dengan traffic di bawah 10.000 orders per hari, Doctrine transport sudah sangat cukup. Jangan over-engineer — mulai dengan yang simple, upgrade ketika bottleneck terjadi.

Tips Performance

  1. Batch processing: Untuk tasks yang bisa di-batch (misal: kirim 100 email sekaligus), kelompokkan messages dan proses dalam satu handler.
  2. Priority queues: Buat transport terpisah untuk tasks yang urgent (payment confirmation) vs non-urgent (analytics update).
  3. Delayed messages: Gunakan stamp DelayStamp untuk message yang harus diproses nanti (misal: review reminder 3 hari setelah purchase).
  4. Failed message handling: Konfigurasi failure transport untuk menyimpan message yang gagal. Review dan retry secara berkala.

Symfony Messenger adalah salah satu fitur terbaik di ekosistem Symfony. Dengan overhead minimal (0 dependency tambahan jika pakai Doctrine transport), Anda bisa mengubah aplikasi monolith menjadi arsitektur yang lebih resilient dan responsive. Untuk VPS 1GB RAM seperti yang umum dipakai developer Indonesia, ini adalah solusi ideal.

Bagikan artikel ini
Chat Kami