Symfony Messenger: Kuyruklar, Worker'lar ve Asenkron Mimari Mulakat Sorulari 2026

Symfony Messenger bileseninin mesaj bus mimarisi, transport yapilandirmasi, worker yonetimi, deduplication middleware, retry stratejileri ve Symfony 7.3+ streaming AMQP transport konularini kapsayan teknik mulakat rehberi.

Symfony Messenger asenkron kuyruk ve worker mimarisi semasi

PHP uygulamalarinda HTTP istegi icerisinde gerceklestirilen agir islemler, kullanici deneyimini dogrudan olumsuz etkilemektedir. Fatura PDF'i olusturma, toplu e-posta gonderimi veya ucuncu parti API cagrisi gibi islemler, yanit suresini saniyeler mertebesinde uzatabilmektedir. Symfony Messenger bileseni, bu tur islemleri ana istek dongusunden ayirarak bir mesaj bus, yapilandirilmis transport katmanlari ve denetimli worker surecleri araciligiyla asenkron olarak islemektedir. Symfony 7.3 ve 8.0 surumlerinde eklenen DeduplicateMiddleware, Doctrine keepalive destegi ve #[AsMessage] attribute'u ile birlikte Messenger, kurumsal olcekte asenkron is yuku yonetimi icin tam donanimli bir bilesene donusmustur.

Symfony 7.3+ Messenger Onemli Yenilikler

Symfony 7.3 ile birlikte mesaj tekrarlarini otomatik olarak engelleyen DeduplicateMiddleware, uzun sureli islemlerde yeniden teslimi onleyen Doctrine transport keepalive ve transport yonlendirmesini dogrudan mesaj sinifinda tanimlayan #[AsMessage] attribute'u kullanima sunulmustur. Bu yenilikler, ozellikle teknik mulakatlarda sikca sorulan konular arasinda yer almaktadir.

Symfony Messenger Mimarisi: Bus, Transport ve Worker

Messenger bileseni uc temel katmandan olusmaktadir. Bus katmani mesajlarin gonderilmesinden ve middleware zincirinden gecirilmesinden sorumludur. Transport katmani mesajlarin bir kuyruk sistemine serilestirilerek yazilmasini ve okunmasini yonetmektedir. Worker katmani ise transport'tan alinan mesajlari ilgili handler'a ileterek fiili islemi gerceklestirmektedir.

Bir mesaj, yalnizca skaler veri tasiyan sade bir PHP nesnesidir. Doctrine entity'leri veya karmasik nesne grafikleri mesaj icerisinde tasimmamalidir; bunun yerine yalnizca ID degerleri gonderilmeli ve handler isleme aninda veritabanindan guncel kaydi cekmelidir. Bu yaklasim hem serilestirme sorunlarini ortadan kaldirmakta hem de kuyrukta bekleme suresi boyunca verinin degismis olma ihtimaline karsi koruma saglamaktadir.

src/Message/InvoiceGenerated.phpphp
namespace App\Message;

final readonly class InvoiceGenerated
{
    public function __construct(
        public int $orderId,
        public string $customerEmail,
    ) {}
}

Handler, __invoke metodu uzerinden cagrilabilen ve #[AsMessageHandler] attribute'u ile isaretlenen bir siniftir. Symfony'nin autowiring mekanizmasi, __invoke metodunun parametre tipine bakarak handler'i ilgili mesaj sinifiyla otomatik olarak eslestirmektedir.

src/MessageHandler/InvoiceGeneratedHandler.phpphp
namespace App\MessageHandler;

use App\Message\InvoiceGenerated;
use App\Service\InvoiceService;
use App\Service\MailerService;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler]
final readonly class InvoiceGeneratedHandler
{
    public function __construct(
        private InvoiceService $invoiceService,
        private MailerService $mailerService,
    ) {}

    public function __invoke(InvoiceGenerated $message): void
    {
        $pdf = $this->invoiceService->generatePdf($message->orderId);
        $this->mailerService->sendInvoice(
            $message->customerEmail,
            $pdf,
        );
    }
}

Bir controller veya servis icerisinden mesaj gondermek son derece yalindi. Bus, yapilandirmaya gore mesaji senkron veya asenkron olarak islemeye yonlendirmektedir.

src/Controller/OrderController.phpphp
$this->bus->dispatch(new InvoiceGenerated(
    orderId: $order->getId(),
    customerEmail: $order->getCustomer()->getEmail(),
));

Eger ilgili mesaj icin bir transport tanimlanmamissa handler ayni HTTP istegi icerisinde dogrudan calistirilmaktadir. Transport tanimlandigi anda ise mesaj kuyruga yazilmakta ve worker sureci tarafindan ayri bir anda islenmektedir. Senkron ve asenkron modlar arasindaki gecis tamamen yapilandirma duzeyli olup uygulama kodunda herhangi bir degisiklik gerektirmemektedir.

Transport Yapilandirmasi ve Kuyruk Altyapilari

Messenger bileseni; Doctrine DBAL, Redis, Amazon SQS, Beanstalkd, AMQP (RabbitMQ) ve 2025 yilinda tanitilan streaming AMQP transport dahil olmak uzere cok sayida kuyruk altyapisini desteklemektedir. Her transport bir DSN dizesi uzerinden tanimlanmaktadir.

Asagidaki yapilandirma, oncelik seviyesine gore ayrilmis iki transport ve bir basarisizlik transport'u icerir:

yaml
# config/packages/messenger.yaml
framework:
    messenger:
        failure_transport: failed

        transports:
            async_priority_high:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    queue_name: high
                retry_strategy:
                    max_retries: 3
                    delay: 1000
                    multiplier: 3
                    max_delay: 60000

            async_priority_low:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    queue_name: low
                retry_strategy:
                    max_retries: 5
                    delay: 5000
                    multiplier: 2

            failed:
                dsn: 'doctrine://default?queue_name=failed'

        routing:
            'App\Message\InvoiceGenerated': async_priority_high
            'App\Message\CleanupTempFiles': async_priority_low

Transport'larin oncelik seviyesine gore ayrilmasi, zamana duyarli islemlerin (fatura olusturma) dusuk oncelikli bakim gorevlerinden (gecici dosya temizligi) once islenmesini garanti altina almaktadir. Her transport icin bagimsiz retry stratejisi tanimlanabilmektedir. Yuksek oncelikli transport'ta multiplier: 3 degeri ile exponential backoff uygulanarak basarisiz mesajlar 1, 3 ve 9 saniye araklarla yeniden denenmektedir.

Doctrine vs. Redis vs. AMQP

Doctrine transport ek altyapi gerektirmeden hizli baslangic saglamakta, ancak veritabani uzerinde ek yuk olusturmaktadir. Redis, milisaniyenin altinda gecikme suresi ile yuksek verimli senaryolara uygundur. AMQP (RabbitMQ) ise gelismis yonlendirme, dead-letter exchange desteği ve yeni streaming transport ile en kapsamli ozellikleri sunmaktadir. Secim, projenin mevcut altyapisina ve verim gereksinimlerine gore yapilmalidir.

Supervisor ile Worker Yonetimi

Worker'lar, transport'lardan mesajlari okuyan ve handler'lara ileten sureclerdir. Gelistirme ortaminda messenger:consume komutu dogrudan terminalden calistirilabilirken, uretim ortaminda bu sureclerin Supervisor veya systemd gibi bir surec yoneticisi altinda calistirilmasi zorunludur. Surec yoneticisi, beklenmedik cokmelerde otomatik yeniden baslatma, log rotasyonu ve surec izleme yetenekleri saglamaktadir.

bash
# Consume high-priority messages first, then low-priority
php bin/console messenger:consume async_priority_high async_priority_low \
    --memory-limit=128M \
    --time-limit=3600 \
    --limit=500

Uc sinir parametresi, worker yasam dongusunu guvenli bir cercevede tutmaktadir. --memory-limit bellek sizintisi riskini bertaraf etmekte, --time-limit uzun sureli PHP sureclerinin kaynakla ilgili sorunlarini onlemekte ve --limit belirli sayida mesajdan sonra surecin yeniden baslatilmasini saglamaktadir.

ini
; /etc/supervisor/conf.d/messenger-worker.conf
[program:messenger-consume]
command=php /var/www/app/bin/console messenger:consume async_priority_high async_priority_low --memory-limit=128M --time-limit=3600
user=www-data
numprocs=2
process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
startsecs=0
stopwaitsecs=30
stdout_logfile=/var/log/messenger-worker.log
stderr_logfile=/var/log/messenger-worker-error.log

numprocs=2 ayari iki paralel worker baslatarak mesaj isleme kapasitesini ikiye katlamaktadir. Bu deger sunucunun CPU cekirdek sayisina ve mesajlarin ortalama isleme suresine gore ayarlanmalidir. stopwaitsecs=30 parametresi, worker kapanirken islenmekte olan mesajin tamamlanmasina yeterli sureyi tanimaktadir. Mulakatlarda Supervisor yapilandirmasinin nedenleriyle birlikte aciklanmasi beklenmektedir.

Middleware Pipeline ve CQRS

Middleware katmani, her mesaj gonderimi sirasinda calisarak cross-cutting concern'leri (dogrulama, transaction yonetimi, loglama gibi) merkezi olarak yonetmektedir. Birden fazla bus tanimlayarak CQRS (Command Query Responsibility Segregation) kalibini uygulamak mumkundur.

yaml
# config/packages/messenger.yaml
framework:
    messenger:
        default_bus: command.bus
        buses:
            command.bus:
                middleware:
                    - validation
                    - doctrine_transaction
            query.bus:
                middleware:
                    - validation
            event.bus:
                default_middleware:
                    allow_no_handlers: true
                middleware:
                    - validation

Komut bus'i (command.bus), durum degisikligi yaratan islemleri bir Doctrine transaction icerisinde atomik olarak yurutmektedir. Sorgu bus'i (query.bus), salt okunur islemler icin transaction ek yukunden muaftir. Olay bus'i (event.bus) ise allow_no_handlers: true ayari sayesinde henuz dinleyicisi olmayan olaylarin hata firlatmadan yayinlanmasina olanak tanimaktadir. Bu mimari ayrimi, kod tabaninin olceklenebilirligini ve test edilebilirligini onemli olcude artirmaktadir.

Symfony mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Symfony 7.3 Deduplication Middleware

Dagitik sistemlerde ag gecikmeleri, istemci yeniden denemeleri veya yarisma kosullari nedeniyle ayni mesajin birden fazla kez kuyruga eklenmesi sikca yasanan bir durumdur. Tekrarlanan mesajlar, kaynak israfinin otesinde musteriye cift fatura kesilmesi veya ayni e-postanin birden fazla gonderilmesi gibi ciddi yan etkilere yol acabilmektedir. Symfony 7.3 ile sunulan DeduplicateMiddleware, kuyrukta zaten bekleyen ayni mesajlarin otomatik olarak atlanmasini saglamaktadir.

src/Message/SendWelcomeEmail.phpphp
namespace App\Message;

use Symfony\Component\Messenger\Stamp\DeduplicateStamp;

final readonly class SendWelcomeEmail
{
    public function __construct(
        public int $userId,
    ) {}
}
php
// Dispatching with deduplication
use Symfony\Component\Messenger\Stamp\DeduplicateStamp;

$this->bus->dispatch(
    new SendWelcomeEmail(userId: 42),
    [new DeduplicateStamp(id: 'welcome-email-42')],
);

DeduplicateStamp, bir kilit kaynak tanimlayicisi (lock resource identifier) almaktadir. Ayni ID'ye sahip bir mesaj kuyrukta zaten mevcutsa, yeni gonderim sessizce dusurulmektedir. Bu mekanizma, Lock bileseni ile birlikte serilestirilebilir bir depolama alani (Redis, Memcached veya veritabani) gerektirmektedir. Odemeler, bildirimler ve e-posta gonderimleri gibi tekrarlarin ciddi sonuclara yol acabilecegi senaryolarda bu ozellik vazgecilmez bir guvenlik katmani olusturmaktadir.

Retry Stratejileri ve Failure Transport

Bir handler istisna firlattiginda Messenger, ilgili transport'un retry stratejisine gore mesaji otomatik olarak yeniden islemektedir. Tum retry haklari tukendikten sonra mesaj, failure transport'a tasinmaktadir. Ancak her hata ayni kategoride degildir ve Symfony bu ayrimi iki ozel istisna sinifi ile net bir sekilde ortaya koymaktadir.

src/MessageHandler/PaymentHandler.phpphp
namespace App\MessageHandler;

use App\Message\ProcessPayment;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Exception\RecoverableMessageHandlingException;

#[AsMessageHandler]
final class PaymentHandler
{
    public function __invoke(ProcessPayment $message): void
    {
        try {
            $this->gateway->charge($message->amount, $message->token);
        } catch (GatewayTimeoutException $e) {
            // Recoverable: retry with backoff
            throw new RecoverableMessageHandlingException(
                'Payment gateway timeout, retrying',
                previous: $e,
            );
        } catch (InvalidCardException $e) {
            // Unrecoverable: send to failure transport immediately
            throw new UnrecoverableMessageHandlingException(
                'Invalid card, no retry',
                previous: $e,
            );
        }
    }
}

RecoverableMessageHandlingException firlatildiginda mesaj, yapilandirilan gecikme suresiyle yeniden kuyruga eklenmektedir. UnrecoverableMessageHandlingException ise retry mekanizmasini tamamen devre disi birakarak mesaji dogrudan failure transport'a yonlendirmektedir. Bu iki istisna sinifinin dogru kullanilmasi, kalici hatalar uzerinde gereksiz retry tuketimini onlemekte ve operasyonel verimliligi artirmaktadir.

bash
# Inspect and manage failed messages
php bin/console messenger:failed:show
php bin/console messenger:failed:show 20 --transport=failed

# Retry specific messages
php bin/console messenger:failed:retry 20 30

# Filter and remove by class (Symfony 7.3+)
php bin/console messenger:failed:remove --class-filter="App\Message\CleanupTempFiles"
Idempotant Handler Tasarimi

Retry mekanizmasi, bir handler'in ayni mesaj icin birden fazla calistirilabilecegi anlamina gelmektedir. Bu nedenle her handler idempotant olarak tasarlanmalidir: islem oncesinde o isin daha once tamamlanip tamamlanmadigini kontrol etmelidir. Veritabani benzersiz kisitlamalari, durum bayraklari veya distributed lock mekanizmalari kullanilarak cift isleme riski minimize edilmelidir.

Doctrine Keepalive ve Uzun Sureli Mesajlar

Buyuk PDF raporu olusturma veya kapsamli veri seti isleme gibi uzun sureli handler'lar, transport'un gorunurluk zaman asimini (visibility timeout) asabilmektedir. Varsayilan zaman asimi suresi dolugunda transport, mesajin islenmedigi sonucuna vararak baska bir worker'a yeniden teslim etmektedir. Bu durum ayni mesajin birden fazla worker tarafindan es zamanli olarak islenmesine yol acmaktadir. Symfony 7.2 ile Redis, SQS ve Beanstalkd icin eklenen keepalive destegi, Symfony 7.3'te Doctrine transport'una da genisletilmistir.

bash
# Enable keepalive to prevent redelivery during long processing
php bin/console messenger:consume async --keepalive

--keepalive parametresi, Doctrine transport tablosundaki delivered_at zaman damgasini periyodik olarak guncelleyerek worker'in mesaji hala aktif olarak islemekte oldugunu bildirmektedir. Bu mekanizma transport katmaninda seffaf bir sekilde calismakta olup handler kodunda herhangi bir degisiklik gerektirmemektedir. Tek yapilmasi gereken consumer komutuna bu bayragi eklemektir.

#[AsMessage] Attribute ile Bildirimsel Yonlendirme

Symfony 7.2 ile tanitilan #[AsMessage] attribute'u, transport yonlendirmesini YAML yapilandirmasindan dogrudan mesaj sinifina tasimaktadir. Geleneksel yaklasimda tum yonlendirmeler messenger.yaml dosyasinin routing bolumunde merkezi olarak tanimlanmaktadir. Proje buyudukce bu dosya karmasiklasabilmekte ve bir mesajin hangi transport'a yonlendirildigini bulmak icin ayri bir dosyanin incelenmesi gerekmektedir.

src/Message/GenerateReport.phpphp
namespace App\Message;

use Symfony\Component\Messenger\Attribute\AsMessage;

#[AsMessage(transport: 'async_priority_low')]
final readonly class GenerateReport
{
    public function __construct(
        public int $reportId,
        public string $format = 'pdf',
    ) {}
}

Bu yaklasimla ilgili mesajin transport bilgisi kaynak kodun kendisinde yer almakta ve kod tabani kendi kendini belgelemektedir. YAML yonlendirmesi ve attribute tabanli yonlendirme bir arada kullanilabilmekte olup attribute her zaman oncelik tasimaktadir. Mulakat baglaminda bu ozellik, "convention over configuration" ilkesinin Symfony ekosistemine nasil uyarlandigina dair guzel bir ornek teskil etmektedir.

Streaming AMQP Transport ile Yuksek Verimli Kuyruklar

Klasik AMQP transport'u, mesajlari almak icin yoklama (polling) yontemini kullanmaktadir. Her yoklama cagrisinda kuyrukta mesaj olmasa dahi bir ag istegi gerceklesmekte ve bu durum yuksek frekansta gereksiz kaynak tuketimine neden olmaktadir. 2025 yilinda yayimlanan streaming AMQP transport, itme (push) modeline gecerek gecikmeyi ve kaynak kullanimini onemli olcude azaltmaktadir.

yaml
# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            streaming:
                dsn: 'amqp-lib://guest:guest@localhost:5672/%2f/messages'
                options:
                    exchange:
                        name: app_events
                        type: topic
                    queues:
                        order_events:
                            binding_keys: ['order.*']

Klasik AMQP transport'undan temel farklari sunlardir: C uzantisi gerektirmeden php-amqplib kullanilmasi, uzun omurlu TCP baglantilari uzerinden akisli teslimat ve topic exchange'ler ile binding key yonlendirmesinin yerel destegi. Bu transport, minimum CPU ek yukuyle saniyede binlerce mesaji isleyebilmekte ve ozellikle mikroservis mimarilerinde farkli servislerin belirli olay turlerini dinlemesi gereken senaryolarda buyuk esneklik saglamaktadir.

Sonuc

Symfony Messenger, PHP dunyasinda asenkron is yuku yonetimi icin en kapsamli ve olgun bilesenlerden biri konumundadir. 2026 yili itibaryla teknik mulakatlarda ozellikle su noktalarin bilinmesi beklenmektedir:

  • Mesajlarda Doctrine entity'leri degil skaler ID'ler tasinmali; handler isleme aninda veritabanindan guncel veri cekmelidir
  • Transport'lar oncelik ve kritiklik seviyesine gore ayrilmali; her transport'a bagimsiz retry stratejisi tanimlanmalidir
  • RecoverableMessageHandlingException ve UnrecoverableMessageHandlingException kullanilarak retry davranisi acikca kontrol edilmelidir
  • Doctrine transport worker'larinda --keepalive parametresi etkinlestirilerek uzun sureli mesajlarin yeniden teslimi onlenmelidir
  • Cift islemenin yan etkilere yol actigi senaryolarda (odemeler, e-postalar, bildirimler) DeduplicateStamp uygulanmalidir
  • Birden fazla bus ile CQRS uygulanmali: transaction destekli command bus, salt okunur query bus ve pub/sub icin event bus
  • Uretim ortaminda Supervisor veya systemd ile --memory-limit, --time-limit ve --limit parametreleri kullanilarak worker yasam dongusu yonetilmelidir
  • Yuksek verimli senaryolarda streaming AMQP transport tercih edilmelidir

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#symfony
#messenger
#php
#async
#message queue
#workers

Paylaş

İlgili makaleler