Algoritma: Dedup & İdempotency
I₂ invariant'ı: Aynı messageId (veya idempotencyKey) ile gelen olay yalnızca bir kez işlenir.
Akış Şeması (Gateway)
Sıra Diyagramı
Pseudocode: Dedup Kontrolü
FUNCTION onPublish(ws, topic, messageId, payload):
clientId = ws.userId
key = "dedup:" + clientId
IF stateStore.sismember(key, messageId) THEN
RETURN { status: "duplicate" } // İşleme, sadece ACK dönebilirsin
END IF
stateStore.sadd(key, messageId)
stateStore.expire(key, DEDUP_TTL_SECONDS) // Örn. 3600
publishToBackbone(topic, { messageId, payload, seqNo: nextSeq(topic) })
RETURN { status: "ok" }Depolama Seçenekleri
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Redis Set | Hızlı, dağıtık, TTL | Redis bağımlılığı |
| In-memory Map<clientId, Set<messageId>> | Çok hızlı | Gateway restart'ta kayıp; tek gateway |
| DB tablo (processed_ids) | Kalıcı | Gecikme, yük |
Fintech'te genelde Redis Set + TTL (örn. 1 saat) kullanılır; aynı messageId ile tekrar denemeler engellenir.
Node.js Örneği (Redis ile)
javascript
const redis = require('redis');
const client = redis.createClient({ url: process.env.REDIS_URL });
async function ensureDedup(clientId, messageId, ttlSeconds = 3600) {
const key = `dedup:${clientId}`;
const added = await client.sAdd(key, messageId);
if (added === 0) return { duplicate: true }; // Zaten vardı
await client.expire(key, ttlSeconds);
return { duplicate: false };
}
// PUBLISH handler içinde:
const { duplicate } = await ensureDedup(ws.userId, msg.messageId);
if (duplicate) {
ws.send(JSON.stringify({ type: 'ack', messageId: msg.messageId, status: 'duplicate' }));
return;
}
// ... omurgaya yayınla ve ACK(ok) gönderTam gateway örneği: Gateway: ACL + Dedup.