Services

Sink

The sinks services are responsible for projecting a consumed envelope into a durable external storage used for tasks like analytics, baseline computation and traceability.

Every sink follows the same principle: consume records in batches, persist each batch, and only advance the consumer offsets once the batch is durably stored or dead-lettered.

What changes between sinks is how a record is decoded into a domain type, and how a batch of that type is written to storage. Because only those two pieces vary the service creates an abstraction for it allowing for reusability through configuration by environment variables. The deployment contains two sink instances: one for projecting decisions and another one for projecting events.

As mentioned earlier, offsets advance only after the batch is durably persisted or dead-lettered, any failure leaves offsets uncommitted so the records redeliver. This redelivery is safe because inserts are idempotent, a record whose key is already stored is skipped by the database, not duplicated. Transient failures, like the storage service being briefly unavailable, are what redelivery is for. Permanent failures, like corrupted records instead go to a dead-letter queue (DLQ) so they don’t block the partition’s progress.

Sink batch and offset flowRecords are consumed from Kafka, assembled into a batch, decoded and split, persisted or dead-lettered, and then committed through offset 1005. Transient failures leave offsets uncommitted for redelivery.Sink batch & offset flowConsume in batches. Persist or DLQ everything. Advance offsets only after durable handling.1Consume from topic2Batch assembledsize or age3Decode + split4Persist good,DLQ bad5Advance offsetsKafka topic: raw_eventscurrent batchevent-101validevent-102validevent-103bad JSONevent-104validevent-105duplicate5 records in current batchBatchersize = 5orage = 500msfirst record started the timerDecode + splitGood recordsevent-101event-102event-104event-105Bad recordsevent-103decode failedPostgresInsertedevent-101event-102event-104Skipped (already exists)event-105Dead-letter queueevent-103 · dead-letteredAdvance offsetsafter durable handling10011002100310041005committedthrough offset 1005Key principleOffsets advance only after every record is inserted,skipped, or sent to the DLQ.Transient failureStorage unavailable → leave offsets uncommitted→ redeliveryPermanent failureCorrupted record → send to DLQ→ partition progress continues