Kurumsal yazılım, güvenlik ve mühendislik notları
Outbox Pattern, Idempotency ve Retry: Güvenilir Entegrasyon Rehberi
Middleware ve Entegrasyon Mimarisi ·
Yazar: Mehmet DOĞAN
Editör: Mehmet DOĞAN
Outbox pattern nedir, entegrasyonda neden hayat kurtarır?
Outbox pattern (transactional outbox), bir iş kaydını veritabanına yazarken diğer sistemlere gidecek mesajı da aynı transaction içinde bir “giden kutusu” tablosuna yazmanızı, mesajı ise ayrı bir süreçle güvenle yayınlamanızı sağlayan bir tasarım desenidir. Neden gerekli? Çünkü “önce siparişi kaydet, sonra kuyruğa mesaj at” yaklaşımı, iki adım arasında uygulama çöktüğünde ERP’de onaylı ama faturası hiç kesilmemiş siparişler bırakır. Tersi de olur: mesaj gider ama transaction geri alınır, var olmayan bir sipariş için e-Fatura isteği oluşur.
Bu rehber; ERP, e-ticaret, ödeme sağlayıcısı ve e-Fatura özel entegratörü arasında güvenilir veri akışı kurmak zorunda olan yazılım ekipleri ve teknik liderler için yazıldı. Outbox tablosunun tasarımını, relay’in polling veya CDC (Debezium) ile çalıştırılmasını, en az bir kez teslimi, idempotency anahtarlarını, üstel geri çekilme ve jitter ile yeniden denemeyi, zaman aşımlarını, dead-letter kuyruğunu, circuit breaker’ı ve sıralama sorununu PostgreSQL ve TypeScript örnekleriyle anlatıyor. Mimarinin bütün resmi için kurumsal entegrasyon ve ara katman mimarisi yazımızla birlikte okumanızı öneririz.
Kısaca
- Dual-write (veritabanına ve broker’a ayrı ayrı yazmak) iki sistemi tutarsız bırakabilir; outbox bunu tek transaction’a indirger.
- Relay, outbox’taki kayıtları polling (ör.
FOR UPDATE SKIP LOCKED) veya CDC (Debezium) ile yayınlar. - Outbox en az bir kez teslim sağlar; bu yüzden tüketiciler mesaj kimliğiyle tekrarları ayıklamalı, yani idempotent olmalıdır.
- Yeniden deneme; zaman aşımı, üst sınırlı üstel geri çekilme, jitter ve deneme sınırıyla birlikte tasarlanır.
- İşlenemeyen (zehirli) mesajlar DLQ’ya alınır; DLQ’nun sahibi, alarmı ve yeniden işleme prosedürü olur.
• • •
Dual-write problemi nedir?
Chris Richardson’ın microservices.io sitesindeki tanımıyla sorun şudur: bir servis komutu hem veritabanını güncellemeli hem de bir broker’a mesaj göndermelidir ve bu iki işlem atomik olmalıdır. Veritabanını ve broker’ı kapsayan dağıtık transaction (2PC) ise çoğu zaman mümkün değildir ya da istenmez. Transaction ortasında mesaj göndermek güvenilir değildir, çünkü commit olacağının garantisi yoktur; commit’ten sonra göndermek de güvenilir değildir, çünkü servis tam o anda çökebilir.
Somut örnek: ERP siparişi → e-Fatura
Müşteri siparişi onaylandığında ERP’de sipariş “onaylandı” durumuna geçer ve özel entegratöre
fatura isteği gönderilmesi gerekir. Uygulama siparişi commit eder, ardından mesajı gönderirken
bağlantı kopar. Sonuç: sipariş onaylı, fatura yok; muhasebe bunu ay sonu mutabakatında fark eder.
Outbox ile sipariş güncellemesi ve OrderConfirmed olayı aynı transaction’da yazılır;
ya ikisi birden kalıcı olur ya da hiçbiri.
Somut örnek: ödeme geri çağrısı (callback)
Ödeme sağlayıcısı başarılı ödemeyi bir webhook ile bildirir ve sağlayıcılar yanıt alamadıklarında aynı bildirimi tekrar gönderebilir. Uygulamanızın bu bildirimi bir kez “sipariş ödendi” olarak işlemesi, kargo ve fatura süreçlerini bir kez tetiklemesi gerekir. Burada iki desen birlikte çalışır: gelen tarafta idempotent işleme, giden tarafta outbox.
• • •
Transactional outbox nasıl çalışır?
microservices.io’daki desen tanımına göre gönderen servis mesajı, iş varlıklarını güncelleyen transaction’ın parçası olarak veritabanındaki outbox tablosuna yazar; ayrı bir message relay süreci bu mesajları broker’a iletir. Desen üç şey vaat eder: 2PC kullanılmaz, mesajlar yalnızca transaction commit olursa gönderilir ve mesajlar servisin ürettiği sırayla yayınlanır. Aynı kaynak önemli bir uyarıyı da yapar: relay bir mesajı yayınladıktan sonra, bunu kaydedemeden çökerse yeniden başladığında mesajı tekrar yayınlar.
Outbox tablosu tasarımı
Debezium’un Outbox Event Router dokümantasyonu varsayılan yapılandırma için id,
aggregatetype, aggregateid, type ve payload
sütunlarını bekler: aggregatetype hedef topic’i, aggregateid mesaj anahtarını
(dolayısıyla Kafka partition’ındaki sıralamayı) belirler, id ise tekrarları ayıklamak
için başlık olarak taşınır. Polling ile çalışacaksanız yayın durumu ve deneme bilgisi için birkaç
sütun daha eklemek işinizi kolaylaştırır:
-- Outbox: iş verisiyle aynı veritabanında, aynı transaction'da yazılır
CREATE TABLE outbox (
id uuid PRIMARY KEY,
aggregatetype varchar(255) NOT NULL, -- ör. 'order'
aggregateid varchar(255) NOT NULL, -- ör. sipariş numarası (mesaj anahtarı)
type varchar(255) NOT NULL, -- ör. 'OrderConfirmed'
payload jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
published_at timestamptz, -- polling relay için
attempts integer NOT NULL DEFAULT 0,
next_attempt_at timestamptz NOT NULL DEFAULT now(),
last_error text
);
CREATE INDEX outbox_pending_idx
ON outbox (next_attempt_at)
WHERE published_at IS NULL;
-- Uygulama: sipariş güncellemesi ve olay tek transaction'da
BEGIN;
UPDATE orders SET status = 'CONFIRMED' WHERE id = $1;
INSERT INTO outbox (id, aggregatetype, aggregateid, type, payload)
VALUES ($2, 'order', $1, 'OrderConfirmed', $3::jsonb);
COMMIT;
Relay: polling mi, CDC mi?
Polling relay, bekleyen kayıtları belirli aralıklarla okuyup yayınlar. PostgreSQL
dokümantasyonu, SKIP LOCKED seçeneğinin hemen kilitlenemeyen satırları atladığını ve
bunun genel amaçlı sorgular için uygun olmasa da birden fazla tüketicinin kuyruk benzeri bir
tabloyu okumasında kilit çekişmesini önlemek için kullanılabileceğini belirtir. Basit, ek altyapı
istemez; dezavantajı sorgu yükü ve polling aralığı kadar gecikmedir.
-- Birden fazla relay örneği aynı satırı almadan çalışabilir
SELECT id, aggregatetype, aggregateid, type, payload, attempts
FROM outbox
WHERE published_at IS NULL
AND next_attempt_at <= now()
ORDER BY created_at
LIMIT 100
FOR UPDATE SKIP LOCKED;
CDC relay ise veritabanının işlem günlüğünü (transaction log) okur. Debezium projesinin 2019 tarihli outbox yazısında Gunnar Morling, log tabanlı CDC’nin polling yaklaşımına göre çok düşük ek yükle ve neredeyse gerçek zamanlı çalıştığını anlatır. Aynı yazıdaki ilginç bir ayrıntı: kayıt eklenip aynı transaction’da silinse bile INSERT olayı günlükte yer aldığı için yayınlanır; tablo sürekli boş kalır ve ayrı bir temizlik işine gerek olmaz. Bedeli, Kafka Connect ve Debezium operasyonunu üstlenmektir.
• • •
Teslim garantileri: en çok bir kez, en az bir kez, fiilen bir kez
Confluent dokümantasyonu üç semantiği şöyle tanımlar: en çok bir kez (at-most-once) teslimde hata olursa mesaj kaybolabilir ama tekrar gönderilmez; en az bir kez (at-least-once) teslimde mesaj kaybolmaz ama birden fazla kez gelebilir; tam bir kez (exactly-once) ise her mesajın yalnızca bir kez teslim edilmesidir. Kafka, 0.11.0.0 sürümünden itibaren idempotent producer ve transaction’larla Kafka içinde tam bir kez işlemeyi destekler; ancak aynı doküman, dış bir sisteme yazarken bu koordinasyonun zorlaştığını ve Kafka’nın varsayılan olarak en az bir kez garanti verdiğini vurgular.
Pratikte bir ERP’den özel entegratöre uzanan zincirde ulaşabileceğiniz hedef, fiilen bir kez (effectively-once) etkidir: mesaj birden fazla kez gelebilir, ama iş sonucu bir kez oluşur. Bunu sağlayan şey broker ayarı değil, tüketicinin idempotent tasarımıdır.
| Semantik | Ne garanti eder? | Risk | Maliyet / karmaşıklık | Uygun senaryo |
|---|---|---|---|---|
| En çok bir kez | Tekrar yok | Mesaj kaybı | Düşük | Metrik, log, kaybı tolere edilebilen bildirim |
| En az bir kez | Kayıp yok | Tekrar eden mesaj | Orta: onay, retry, kalıcı kuyruk | Sipariş, fatura, stok olayları (idempotent tüketiciyle) |
| Fiilen bir kez | Kayıp yok, iş etkisi tek | Tasarım hatası olursa sessiz tekrar | Yüksek: outbox, mesaj kimliği, tekrar tablosu | Ödeme, e-Fatura, muhasebe kayıtları |
• • •
Idempotency anahtarı ve tekrar tablosu nasıl tasarlanır?
microservices.io’daki Idempotent Consumer deseni, tüketicinin işlediği mesajların kimliklerini
veritabanında saklamasını önerir. Mesaj işlenirken transaction açılır, mesaj kimliği
(subscriberId, messageId) birincil anahtarlı bir tabloya eklenir; mesaj daha önce
işlendiyse ekleme başarısız olur ve mesaj yok sayılır. RabbitMQ’nun güvenilirlik rehberi de ağ veya
düğüm hatasında mesajların yeniden teslim edilebileceğini ve tüketicilerin bunu idempotent tasarımla
karşılamasının önerildiğini belirtir.
CREATE TABLE processed_messages (
consumer_id text NOT NULL, -- ör. 'efatura-adapter'
message_id uuid NOT NULL, -- outbox.id (mesaj başlığından)
processed_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (consumer_id, message_id)
);
Dışarıya giden çağrılarda idempotency
Stripe’ın API dokümantasyonu iyi bir referanstır: istemci her yazma isteğine bir
Idempotency-Key başlığı ekler; sunucu ilk isteğin durum kodunu ve gövdesini, başarılı
olsun olmasın (500 hataları dahil) saklar ve aynı anahtarla gelen sonraki istekler aynı sonucu alır.
Stripe anahtar olarak V4 UUID gibi yeterli rastgelelikte değerler önerir, anahtarı en fazla 255
karakterle sınırlar, en az 24 saat geçmiş anahtarların temizlenebileceğini belirtir ve aynı anahtarla
farklı parametre gönderilirse hata döner. Anahtara e-posta gibi kişisel veri koymamak da aynı
dokümanın uyarısıdır.
Her özel entegratör veya banka API’si böyle bir başlık sunmaz. Sunmuyorsa iki yol vardır: faturaya sizin tarafınızda atanan benzersiz kimlikle “önce sorgula, yoksa gönder” akışı kurmak ya da gönderilen isteği ve sonucu yerel bir tabloda kaydedip tekrar göndermeden önce kontrol etmek. Hangi yolun mümkün olduğu, sağlayıcının dokümantasyonunda keşif aşamasında doğrulanmalıdır. Güncel e-Fatura format değişikliklerinin entegrasyona etkisi için GİB UBL-TR güncellemesi yazımıza bakabilirsiniz.
• • •
Retry, timeout ve jitter nasıl ayarlanır?
AWS Builders’ Library’deki “Timeouts, retries, and backoff with jitter” makalesi bu konunun en sağlam kaynaklarından biridir. Temel tavsiyeler şunlardır: her uzak çağrıya hem bağlantı hem istek zaman aşımı koyun; yeniden denemeleri “bencil” kabul edin, çünkü aşırı yüklenmiş bir sistemi daha da yükleyebilir; üstel geri çekilmeyi bir üst sınırla kullanın ve deneme sayısını sınırlayın.
Katmanlı retry tuzağı
Aynı makale çarpıcı bir örnek verir: beş katmanlı bir çağrı zincirinde her katman üç kez yeniden denerse, veritabanı üzerindeki yük 243 katına çıkabilir. Bu yüzden yeniden denemeyi zincirin tek bir noktasında yapın. Outbox mimarisinde bu nokta genellikle relay ve tüketicidir; HTTP istemci kütüphanesinin kendi gizli retry’ını da ayrıca açık bırakmayın.
Jitter: aynı anda geri dönmeyin
Marc Brooker’ın AWS Architecture Blog’daki 2015 tarihli yazısı “Full Jitter”, “Equal Jitter” ve “Decorrelated Jitter” yaklaşımlarını simülasyonla karşılaştırır: jitter’sız üstel geri çekilme hem daha fazla iş hem daha uzun süre gerektirerek açık ara en kötü sonucu verir; Full Jitter daha az çağrı yapar. Kural basittir: bekleme süresini sıfır ile o denemenin üst sınırı arasında rastgele seçin.
Hangi hatalar yeniden denenir?
AWS makalesi, yan etkisi olan API’lerin idempotent değilse yeniden denenmesinin güvenli olmadığını ve istemci hatalarının (4xx) aynı istekle tekrarlanmaması gerektiğini, sunucu hatalarının ise sonraki denemede başarılı olabileceğini belirtir. Zaman aşımı, bağlantı hatası ve geçici sunucu hataları yeniden denenir; doğrulama ve yetki hataları denenmez, doğrudan DLQ’ya ve insan incelemesine gider.
// Relay işçisi (sözde kod): yayınla, işaretle; hata olursa jitter ile ertele
const BASE_MS = 1_000
const CAP_MS = 30_000
const MAX_ATTEMPTS = 8
function backoffWithJitter(attempt: number): number {
const ceiling = Math.min(CAP_MS, BASE_MS * 2 ** attempt)
return Math.floor(Math.random() * ceiling) // Full Jitter
}
async function relayBatch(db: Db, broker: Broker): Promise<void> {
await db.transaction(async (tx) => {
const rows = await tx.query(SELECT_PENDING_SQL) // FOR UPDATE SKIP LOCKED
for (const row of rows) {
try {
await broker.publish(row.aggregatetype, {
key: row.aggregateid, // aynı sipariş → aynı partition
headers: { 'message-id': row.id }, // tüketici tekrarları bununla ayıklar
value: row.payload,
}, { timeoutMs: 5_000 })
await tx.query('UPDATE outbox SET published_at = now() WHERE id = $1', [row.id])
} catch (err) {
const attempts = row.attempts + 1
if (attempts >= MAX_ATTEMPTS) {
await moveToDeadLetter(tx, row, err) // alarm + insan incelemesi
continue
}
await tx.query(
`UPDATE outbox
SET attempts = $2,
next_attempt_at = now() + ($3 || ' milliseconds')::interval,
last_error = $4
WHERE id = $1`,
[row.id, attempts, backoffWithJitter(attempts), String(err)],
)
}
}
})
}
• • •
Dead-letter kuyruğu, zehirli mesajlar ve circuit breaker
Zehirli mesaj (poison message), kaç kez denenirse denensin işlenemeyecek mesajdır: bozuk JSON, eşlemesi olmayan bir ürün kodu, vergi numarası hatalı bir cari. Böyle bir mesajı sonsuza kadar yeniden denemek kuyruğu tıkar ve arkasındaki sağlıklı mesajları bekletir. RabbitMQ, bir mesajın yeniden kuyruğa alınmadan reddedilmesi, TTL süresinin dolması, kuyruk uzunluk sınırının aşılması veya quorum kuyruklarda teslim sınırının geçilmesi durumlarında dead-letter exchange’e yönlendirilmesini destekler.
DLQ işletme kuralları
- DLQ’ya düşen her mesaj; orijinal mesaj kimliği, hata nedeni, deneme sayısı ve correlation id ile saklanır.
- DLQ derinliği için alarm vardır ve alarmın bir sahibi (kişi veya nöbet rotası) bulunur.
- Hata giderildikten sonra mesajın yeniden işlenmesi idempotent olduğu için güvenlidir; prosedür runbook’ta yazılıdır.
- DLQ’daki mesajlar süresiz bekletilmez; saklama süresi ve kişisel veri içeriği KVKK açısından değerlendirilir.
Circuit breaker
Martin Fowler’ın 2014 tarihli yazısında anlattığı circuit breaker, korunan uzak çağrıyı bir nesneyle sarar; hata sayısı eşiği geçtiğinde devre “açılır” ve sonraki çağrılar uzak sisteme hiç gitmeden hata döner. Belirli bir süre sonra “yarı açık” duruma geçilir ve deneme çağrısı başarılı olursa devre kapanır. Fowler, durum değişikliklerinin loglanmasını ve izlenmesini de önerir. AWS makalesi ise circuit breaker’ların test edilmesi zor modal davranış getirebildiğini, yerel bir token bucket ile retry’ları sınırlamanın bir alternatif olduğunu not eder. Özel entegratör bakımdayken relay’in faturaları DLQ’ya boca etmek yerine beklemesi, bu desenin en somut faydasıdır.
• • •
Sıralama, saga ve tüketici tarafı
Sıralama ne zaman önemlidir?
“Sipariş oluşturuldu”dan önce “sipariş iptal edildi” işlenirse sorun çıkar. Debezium, outbox
kaydındaki aggregateid değerini mesaj anahtarı yapar; Kafka da aynı anahtarlı olayları
aynı partition’a yazıp o partition’da yazılış sırasını korur. Polling relay’i birden fazla örnekle
ve SKIP LOCKED ile çalıştırırsanız, aynı siparişe ait iki olay farklı örneklerce farklı
sırada yayınlanabilir. Kesin sıra gerekiyorsa ya tek relay örneği, ya anahtar bazında bölümlenmiş
relay’ler ya da CDC tercih edilmeli; tüketici de olaydaki sürüm numarasına bakarak eski olayı yok
sayabilmelidir.
Saga ile birlikte outbox
Birden fazla servise yayılan iş süreçlerinde microservices.io, her biri kendi veritabanını güncelleyip bir sonraki adımı tetikleyen yerel transaction’lardan oluşan saga desenini önerir; bir adım iş kuralı nedeniyle başarısız olursa önceki adımlar telafi (compensating) transaction’larıyla geri alınır. Saga’nın güvenilir çalışması için her adımın veritabanını güncelleyip mesajı atomik olarak yayınlaması gerekir; yani saga’nın altında genellikle outbox vardır.
Tüketici sözde kodu
// e-Fatura adaptörü: aynı mesaj ikinci kez gelirse hiçbir şey yapmaz
async function handleOrderConfirmed(msg: Message): Promise<void> {
await db.transaction(async (tx) => {
const res = await tx.query(
`INSERT INTO processed_messages (consumer_id, message_id)
VALUES ('efatura-adapter', $1)
ON CONFLICT DO NOTHING`,
[msg.headers['message-id']],
)
if (res.rowCount === 0) return // tekrar: zaten işlendi
const invoice = mapOrderToInvoice(msg.value) // kanonik model → fatura
await tx.query(
'INSERT INTO invoice_requests (order_id, payload, status) VALUES ($1, $2, $3)',
[invoice.orderId, invoice, 'PENDING'],
)
})
// Sağlayıcıya gönderim ayrı bir işçide, invoice_requests üzerinden ve
// sağlayıcının desteklediği idempotency yöntemiyle yapılır.
}
• • •
Kontrol listesi: outbox ve retry tasarımı
- İş verisi ve outbox kaydı aynı veritabanında, aynı transaction’da mı yazılıyor?
- Her mesajın benzersiz bir kimliği var ve broker başlığında taşınıyor mu?
- Her tüketici bu kimlikle tekrarları ayıklıyor mu (tekrar tablosu veya doğal anahtar)?
- Her uzak çağrıda bağlantı ve istek zaman aşımı tanımlı mı?
- Retry yalnızca tek bir katmanda, üst sınırlı üstel geri çekilme ve jitter ile mi yapılıyor?
- Doğrulama ve yetki hataları retry’a girmeden DLQ’ya mı gidiyor?
- DLQ için alarm, sahip ve yeniden işleme prosedürü runbook’ta yazılı mı?
- Sıralama gereken olaylar için anahtar ve relay stratejisi belirlendi mi?
- Bekleyen outbox kaydı sayısı ve en eski kaydın yaşı izleniyor mu?
Bu metriklerin nasıl toplanacağını kurumsal uygulamalarda gözlemlenebilirlik yazımızda, outbox tablosu büyüdüğünde PostgreSQL tarafında dikkat edilecekleri ise PostgreSQL okuma ağırlıklı iş yükleri rehberimizde bulabilirsiniz.
Aksiyon Soft nasıl yardımcı olur?
API ve entegrasyon projelerimizde outbox, idempotent tüketici, retry politikası ve DLQ süreçlerini ilk sprintten itibaren tasarımın parçası yapıyoruz; mevcut entegrasyonlarınızda tekrar eden fatura veya kaybolan sipariş sorunları varsa, önce akışı ölçüp en riskli noktadan başlıyoruz. Canlı sistemlerin izlenmesi, DLQ takibi ve olay müdahalesi için bakım ve destek hizmetimiz devreye girer. Mimari bütünü API ve veri entegrasyon platformu çözüm sayfamızda inceleyebilirsiniz.
Çalışma modelimiz: keşifte akış ve hata senaryoları çıkarılır, ilk kritik akışla MVP kurulur, her sprintte çalışan sürüm demo edilir, canlıya geçişten sonra hypercare ve SLA’lı bakım gelir. Merkezimiz Samsun’dadır; Türkiye genelindeki ekiplerle uzaktan çalışır, gerektiğinde planlı saha ziyareti yaparız.
Sık sorulan sorular
Outbox pattern için Kafka şart mı?
Hayır. Outbox, broker’dan bağımsız bir desendir; relay mesajları RabbitMQ’ya, Kafka’ya veya bir HTTP uç noktasına iletebilir. Debezium ile CDC kullanmak istiyorsanız Kafka Connect ekosistemi doğal bir seçimdir, ama polling relay her broker ile çalışır.
Outbox tablosu büyüyüp performansı düşürmez mi?
Polling yaklaşımında yayınlanmış kayıtlar düzenli olarak silinmeli veya arşivlenmelidir; bekleyen kayıtlara kısmi indeks eklemek sorguyu hızlı tutar. CDC yaklaşımında kayıt eklenip hemen silinebilir; Debezium’un outbox yazısında anlatıldığı gibi tablo pratikte boş kalır.
Exactly-once mümkün değil mi?
Kafka, kendi topic’leri arasında transaction’larla tam bir kez işlemeyi destekler. Ancak zincirde özel entegratör, banka veya e-posta servisi gibi dış sistemler olduğunda hedeflenen şey fiilen bir kez etkidir: mesaj birden fazla gelebilir, idempotent tüketici sayesinde iş sonucu bir kez oluşur.
Kaç kez yeniden denemeliyiz?
Evrensel bir sayı yoktur; karşı sistemin toparlanma süresine ve işin aciliyetine göre belirlenir. Önemli olan sınırlı deneme, üst sınırlı üstel geri çekilme, jitter ve sınıra ulaşınca DLQ ile alarmdır. Değerler keşifte yazılır, canlıda metriklere bakılarak ayarlanır.
Webhook ile gelen ödeme bildirimleri nasıl ele alınmalı?
Bildirimi hemen ve hafifçe kabul edip kalıcı olarak kaydedin, asıl işi asenkron yapın. Sağlayıcının bildirim kimliğini tekrar tablosunda kullanarak aynı bildirimin ikinci kez işlenmesini engelleyin; siparişi “ödendi” yapan güncelleme ile kargo/fatura olayını aynı transaction’da outbox’a yazın.
Mevcut sisteme outbox eklemek büyük bir yeniden yazım gerektirir mi?
Genellikle hayır. En riskli akıştan başlayıp mesaj gönderen kod noktasını outbox’a yazacak şekilde değiştirmek ve bir relay eklemek yeterlidir. Diğer akışlar kademeli olarak taşınır; tüketicilere tekrar tablosu eklemek de çoğu zaman küçük bir değişikliktir.
Projenizi konuşalım
Tekrar kesilen faturalar, ERP’ye düşmeyen siparişler veya kimsenin bakmadığı hata kuyrukları yaşıyorsanız, kısa bir keşif görüşmesiyle akışınızı birlikte inceleyelim. İletişim formundan bağlı sistemleri ve sorunun nerede görüldüğünü yazmanız yeterli.
Kaynaklar
- microservices.io (Chris Richardson) — Pattern: Transactional outbox
- microservices.io (Chris Richardson) — Pattern: Idempotent Consumer
- microservices.io (Chris Richardson) — Pattern: Saga
- Debezium Documentation — Outbox Event Router
- Debezium Blog — Gunnar Morling: Reliable Microservices Data Exchange With the Outbox Pattern (19 Şubat 2019)
- Amazon Builders’ Library — Timeouts, retries, and backoff with jitter
- AWS Architecture Blog — Marc Brooker: Exponential Backoff And Jitter (4 Mart 2015)
- Stripe API Reference — Idempotent requests
- Confluent Documentation — Kafka Message Delivery Guarantees
- PostgreSQL Documentation — SELECT (locking clause, SKIP LOCKED)
- martinfowler.com — Martin Fowler: CircuitBreaker (6 Mart 2014)
- RabbitMQ — Reliability Guide
- RabbitMQ — Dead Letter Exchanges
Blog ve haberlere abone olun
Yeni yazılar yayınlandığında e-posta alın. İstediğiniz zaman abonelikten çıkabilirsiniz.
İlgili içerikler
Yazılım Rehberi
Gaziantep Yazılım Ortağı: İhracat ERP, e-Belge ve B2B Portallar
Gaziantep yazılım ihtiyaçlarını tekstil, halı ve gıda ihracatçıları açısından ele alıyoruz: ihracat ERP, e-Fatura ve gümrük entegrasyonu, çok tesisli üretim ve B2B bayi portalları.
Yazılım Rehberi
Malatya Yazılım Ortağı: Kayısı, İhracat ve İş Sürekliliği İçin Kurumsal Yazılım
Malatya yazılım ihtiyaçlarını kayısı işleme ve ihracatı, OSB tekstili ve deprem sonrası yeniden yapılanma açısından ele alıyoruz: izlenebilirlik, ihracat belgeleri, bulut yedekleme ve iş sürekliliği.