Another version of the second diagram with more details:
On the real example, when you close a consumer you are using a new consumer.
Just use that as implicit on the diagram. Or else you would have too many participants and it would be harder to draw it.
BTW: rollback would be the same case. The issue is QueueImpl::asyncDelivery working independenty of the threads used on the repplication.
I'm using www.websequencediagrams.com for these.
This URL has a few changes I made:
There is a race between QueueImpl::deliveryAsync and the repplication of the deliveries.
ServerConsumer will handle a message and it will replicate it on the ServerConsumer(Backup).
When the delivery call arrives on the backup node, the backup's list could be already different than what it was on live node, because of the races caused by QueueImpl.
I think I can understand this now.
I believe it can be explained in a more simple use case:
consumer A rolls back message M1 on Queue Q
rollback is replicated
delivery of message M2 on live to consumer B on Queue Q
delivery is replicated
rollback hits backup and M1 added to top of Q
replicated delivery hits backup looking to find M2 on top of Q but instead find M1