Execution meta — see plan: #5296
Problem
The Runtime records one physical MQ cursor per topic + partition under the reserved __mqcursor__ client ID whenever any delivery is ACKed. In broadcast or multicast delivery, the same physical message is delivered to multiple targets. A fast target can advance this shared cursor while another target still has an unacknowledged copy.
On restart, UniRuntime.alignPullOffsetsToAck() uses the shared cursor to rewind Kafka/RocketMQ 4 pull state. The model cannot represent per-subscriber completion obligations, so a slow target's unacknowledged copy can be skipped or replay behavior can become backend-dependent.
Relevant code:
eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/ingress/UniIngressService.java: pullAndDispatchPartition()
eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/delivery/ReliableDispatcher.java: ack(String)
eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/UniRuntime.java: alignPullOffsetsToAck()
Reproduction
- Use Kafka or RocketMQ 4 with a topic/partition containing one message.
- Register two
BROADCAST subscribers, A and B.
- Deliver the message to both subscribers.
- ACK from A only; leave B unacknowledged.
- Crash/restart the Runtime before B ACKs.
- Verify whether B receives the message again. The required result must not depend on which subscriber ACKed first.
Expected behavior
For broadcast/multicast, recovery must preserve every uncompleted delivery obligation. A physical cursor must not advance past a message until the configured completion rule for that distribution mode is satisfied.
Proposed direction
- Define recovery semantics independently for
LOAD_BALANCE, BROADCAST, and MULTICAST.
- Track physical progress per subscription/group, or persist delivery obligations keyed by topic, physical partition, physical offset, subscription/client, and completion state.
- Derive restart rewind from the minimum incomplete physical position rather than a single global
__mqcursor__ value.
- Document the duplicate-delivery bound for each mode.
Acceptance criteria
Suggested labels
bug, reliability, architecture, priority:p0
Problem
The Runtime records one physical MQ cursor per
topic + partitionunder the reserved__mqcursor__client ID whenever any delivery is ACKed. In broadcast or multicast delivery, the same physical message is delivered to multiple targets. A fast target can advance this shared cursor while another target still has an unacknowledged copy.On restart,
UniRuntime.alignPullOffsetsToAck()uses the shared cursor to rewind Kafka/RocketMQ 4 pull state. The model cannot represent per-subscriber completion obligations, so a slow target's unacknowledged copy can be skipped or replay behavior can become backend-dependent.Relevant code:
eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/ingress/UniIngressService.java:pullAndDispatchPartition()eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/delivery/ReliableDispatcher.java:ack(String)eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/UniRuntime.java:alignPullOffsetsToAck()Reproduction
BROADCASTsubscribers, A and B.Expected behavior
For broadcast/multicast, recovery must preserve every uncompleted delivery obligation. A physical cursor must not advance past a message until the configured completion rule for that distribution mode is satisfied.
Proposed direction
LOAD_BALANCE,BROADCAST, andMULTICAST.__mqcursor__value.Acceptance criteria
Suggested labels
bug,reliability,architecture,priority:p0