An Apache Pekko Streams FlowWithContext can be used instead of a handler for processing the envelopes with at-least-once semantics.
The following example is using the CassandraProjection but the flow would be the same if used any other @ref:offset storage.
Scala : @@snip CassandraProjectionDocExample.scala { #atLeastOnceFlow }
Java : @@snip CassandraProjectionDocExample.java { #atLeastOnceFlow }
The flow should emit a Done element for each completed envelope. The offset of the envelope is carried in the context of the FlowWithContext and is stored in Cassandra when corresponding Done is emitted. Since the offset is stored after processing the envelope, it means that if the projection is restarted from previously stored offset some envelopes may be processed more than once.
There are a few caveats to be aware of:
mapConcat) with same offset, because then it can result in that the first offset is stored and when the projection is restarted that offset is considered completed even though more of the duplicated enveloped were never processed.FlowWithContext rather than ordinary Flow.