Ödeme tamamlanır ve kullanıcı bunu bir saniye içinde, hangi kanalı kullanıyorsa oradan öğrenmek ister. Bunun arkasında tek bir olayı e-postaya, SMS’e, anlık bildirime ve uygulama içi mesaja hiçbirini kaybetmeden dağıtan bir sistem durur. Bu rehber o sistemin mimarisini, teknoloji seçimlerini ve güvenilir kalmasını sağlayan uygulamaları anlatıyor.
Gereksinimler
Gecikme
Kullanıcı bildirimin dakikalar değil, saniyenin altında gelmesini bekler. Sistem olayı işleyip doğru kanala yönlendirmeli ve en az gecikmeyle teslim etmelidir. Fiyatın anlık değiştiği finans uygulamalarında bu bir zorunluluktur.
Teslim garantisi
Bildirimler kullanım durumuna göre en az bir kez ya da en iyi çaba (best effort) garantisiyle iletilir. Dağıtık sistemde uçtan uca “tam bir kez” teslim pratikte en az bir kez teslim ile alıcı tarafta tekrarın elenmesinin birleşimidir. Hatalar, yeniden denemeler ve kesintiler sırasında mesaj kaybolmamalıdır.
Ölçeklenebilirlik
Bir kampanya, önemli bir haber ya da sistem alarmı aynı anda çok sayıda bildirim tetikleyebilir. Mimari yatay ölçeklenmeli ve ani yükte bozulmamalıdır.
Çok kanallı teslim
E-posta, SMS, anlık bildirim (push), uygulama içi mesaj ve webhook. Sistem kanalların farklılıklarını tek bir arayüzün arkasına saklamalıdır.
Mimari
Olay güdümlü temel
Ölçeklenebilir bir bildirim sisteminin temeli olay güdümlü mimaridir. Olay, sistemdeki bir durum değişikliğidir: kullanıcı kaydoldu, ödeme tamamlandı, alarm tetiklendi.
Olay kaynağı → kuyruk → işleyiciler → kanal işleyicileri → kullanıcı
Bu ayrım, ana uygulamanın bildirim teslimiyle hiç uğraşmamasını sağlar. Ödeme tamamlandığında olay kuyruğa yazılır; işleyiciler hangi kanalların kullanılacağına karar verir, mesajı biçimlendirir ve gönderir. Olayı veritabanı kaydıyla aynı transaction’da bir outbox tablosuna yazmak, ödeme kaydedilip bildirimin kaybolması ihtimalini ortadan kaldırır.
Kuyruk seçimi
Apache Kafka: yüksek hacim, kalıcılık ve geçmişi yeniden okuma imkânı. Bir şablon hatasından sonra bildirimleri yeniden işlemek gerektiğinde bu özellik değerlidir.
RabbitMQ: esnek yönlendirme kalıplarıyla güvenilir mesaj aracısı.
AWS SQS/SNS: işletme yükü olmayan yönetilen servisler; SNS filtreli yayınla-abone ol sunar.
Redis Streams: zaten Redis kullanan ve hacmi orta düzeyde olan uygulamalar için hafif bir seçenek.
Uygulama
1. Olayı yayınlamak
from confluent_kafka import Producer
import json
producer = Producer({"bootstrap.servers": "kafka:9092", "enable.idempotence": True})
event = {
"event_id": "evt_01J9...", # tekrarı elemek için benzersiz kimlik
"event_type": "payment_completed",
"user_id": "12345",
"amount_minor": 9999,
"currency": "TRY",
"occurred_at": "2026-01-15T10:30:00Z",
}
# Aynı kullanıcının olayları aynı anahtarla: bölüm içinde sıra korunur
producer.produce("notifications", key=event["user_id"], value=json.dumps(event))
producer.flush()
2. İşleme ve yönlendirme
İşleyici olayı alır, kullanıcının tercihlerine bakar ve kanalları seçer:
def handle(event: dict) -> None:
if already_sent(event["event_id"]): # aynı olay ikinci kez gelirse
return
prefs = get_preferences(event["user_id"]) # önbellekten
message = render("payment_completed", event, locale=prefs.locale)
if prefs.push_enabled:
push.send(event["user_id"], message)
if prefs.email_enabled:
email.send(event["user_id"], message)
if prefs.webhook_url:
webhook.send(prefs.webhook_url, event)
mark_sent(event["event_id"])
Gerçek bir sistemde her kanal ayrı bir kuyruk ve ayrı bir yeniden deneme politikasıyla çalışır; SMS sağlayıcısındaki bir sorun e-postayı bekletmemelidir.
3. Kanal işleyicileri
Kanalları ortak bir arayüzün arkasına alın:
from abc import ABC, abstractmethod
class Channel(ABC):
@abstractmethod
def send(self, recipient: str, message: "Message") -> None: ...
class PushChannel(Channel):
def send(self, recipient, message):
... # FCM, APNs
class EmailChannel(Channel):
def send(self, recipient, message):
... # SMTP ya da e-posta servisi
class SmsChannel(Channel):
def send(self, recipient, message):
... # SMS sağlayıcısı
Sağlayıcıyı değiştirmek ya da ikinci bir sağlayıcıyı yedek olarak eklemek böylece tek bir sınıfı değiştirmek demektir.
Kritik tasarım kararları
Idempotency
Aynı olayın iki kez işlenmesi kullanıcıya iki bildirim göndermemelidir. Her bildirime benzersiz bir anahtar verin ve gönderim öncesi kontrol edin.
Ölü mektup kuyruğu
Belirli sayıda denemeden sonra işlenemeyen mesajlar ayrı bir kuyruğa alınır. Böylece tek bir bozuk mesaj kuyruğu tıkamaz ve sorun sonradan incelenebilir.
İzleme
Her bileşeni ölçün:
- Olaydan teslime uçtan uca gecikme
- Kanal bazında teslim başarı oranı
- Kuyruk derinliği ve işleme hızı
- Yeniden deneme sayıları ve hata sebepleri
Hız sınırı
Hem kullanıcıyı bildirim yağmurundan hem de sistemi aşırı yükten koruyun. Kullanıcı ve kanal başına sınır koyun: pazarlama e-postasını günde bir ile sınırlarken işlemle ilgili bildirimlere (ödeme onayı, güvenlik kodu) sınır koymayın.
Tercihler ve izin
Kullanıcının bildirim tercihlerini hızlı erişilen bir depoda tutun ve her gönderimden önce kontrol edin. Burada iki tür iletiyi ayırmak şarttır:
- İşlemle ilgili iletiler (ödeme onayı, şifre sıfırlama, güvenlik uyarısı) hizmetin parçasıdır.
- Ticari elektronik iletiler (kampanya, indirim, tanıtım) Türkiye’de 6563 sayılı Kanun kapsamındadır. Bireysel alıcılara gönderim için önceden onay gerekir ve onaylar İleti Yönetim Sistemi’ne (İYS) kayıtlı olmalıdır. Gönderimden önce izin İYS’deki duruma göre kontrol edilmeli, alıcının reddi de İYS’den gelebilir.
AB’de GDPR ve ePrivacy, ABD’de CAN-SPAM benzer kurallar koyar. Bu yazı hukuki görüş değildir; kampanya akışını kurmadan önce hukuk ekibinizle doğrulayın.
Ölçekleme
Yatay ölçekleme: işleyici sayısını artırın; Kafka’da tüketici grupları yükü bölümler arasında otomatik dağıtır.
Toplu gönderim: kampanya e-postalarını anında değil, gönderen sunucunun ve sağlayıcının kapasitesine göre zamana yayarak gönderin; ani hacim itibarınızı da zedeler.
Bölgesel sağlayıcılar: SMS’i ülkedeki yerel sağlayıcılar üzerinden göndermek teslim oranını ve maliyeti iyileştirir.
Önbellek: tercihleri, şablonları ve cihaz token’larını önbellekte tutun.
Örnek senaryo
Günde çok sayıda işlem yapılan bir finans uygulamasında bildirim sisteminden beklenenler:
- İşlem onayını saniyenin altında iletmek
- Piyasa hareketlerindeki ani yükü kaldırmak
- E-posta, SMS ve uygulama içi bildirim desteklemek
- Hiçbir işlem bildirimini kaybetmemek
- Finans mevzuatına ve ileti izinlerine uymak
Çözüm: olaylar için Kafka, her kanal için ayrı tüketici grubu, tercihler için Redis önbelleği ve gönderim kayıtları için ayrı, değiştirilemez bir denetim tablosu.
Sonuç
Üretimde ayakta kalan bildirim sistemleri aynı özellikleri paylaşır: gevşek bağlı, yatay ölçeklenebilir, gözlemlenebilir ve hataya dayanıklı. Tek bir kuyruk ve tek bir kanal işleyicisiyle başlayın, karmaşıklığı ancak gerektiğinde ekleyin ve her şeyi ölçün.
Bildirim altyapınızı birlikte tasarlamak isterseniz bize yazın.
ByteGurus
Yazar