Some folks in SigNoz community have also suggested NATS for this, but I have not deep dived into benchmarks/features yet
That's not really "exactly once". What happens when your system dies after it made sure the data is safely stored in the db and before ack-ing?
What if the application doesn't restart before the queue decides the message was lost and resends?
One-or-more semantics + local deduplication gives one-and-only semantics.
In this case you're optimising local deduplication with strictly monotonic index.
One downside is that you leak internals of other system (partitions).
The other is that it implies serialised processing - you can't process anything in parallel as you have single index threshold that defines what has been and what has yet not been processed.
If one-and-only-one semantics are needed and processing should be parallel, other methods have to be used.
> One downside is that you leak internals of other system (partitions).
True, but we generalized the concept of partitions for other datasources, pretty convenient to use it for distributing indexing tasks.
Fortunately Kafka is partitioned. You cannot work in parallel along partitions.
Also, you can streamline your process. If you are running your data through operation (A, B, C). (C on batch N) can run at the same time as (B on batch N+1), and (A on batch N+2)
We do both at quickwit.
You can make the downstream idemptoent wrt what the queue is delivering, but the queue might still redeliver things.
One thing that is also very interesting with Kafka is that you can achieve exactly-once semantic without too much efforts: by keeping track of the positions of partitions in your own database and carefully acknowledging them when you are sure data is safely stored in your db. That's what we did with our engine Quickwit, so far it's the most efficient way to index data in it.
One obvious drawback with Kafka is that it's one more piece to maintain... and it's not a small one.