#[non_exhaustive]pub enum ReplicaEvent {
Frame(DecodedFrame),
Ping(FeedPosition),
SnapshotBegin,
SnapshotChunk(Vec<u8>),
SnapshotEnd {
ack_offset: u64,
},
}Expand description
Event yielded by ReplicaClient::next_event. A driver loop
pattern-matches and applies each:
Self::Frame→ run through the local dispatcher.Self::SnapshotBegin→ caller should reset / prepare the local store for a fresh-from-snapshot fill.Self::SnapshotChunk→ append the bytes to the caller’s accumulating snapshot buffer.Self::SnapshotEnd→ caller hands the accumulated buffer tokevy_persist::load_snapshot;ReplicaClienthas already advancedexpected_offsettoack_offset, so the nextSelf::Framearrives atack_offsetwith no gap.
A replica joining through a snapshot sees the whole sequence:
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
use kevy_replicate::wire;
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
let mut snapshot = Vec::new();
while let Some(event) = client.next_event() {
match event? {
ReplicaEvent::SnapshotBegin => snapshot.clear(),
ReplicaEvent::SnapshotChunk(bytes) => snapshot.extend(bytes),
ReplicaEvent::SnapshotEnd { ack_offset } => assert_eq!(ack_offset, 9),
ReplicaEvent::Frame(frame) => assert_eq!(frame.offset, 9),
_ => {}
}
}
assert_eq!(snapshot, b"dump");Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Frame(DecodedFrame)
A live mutation frame.
use kevy_replicate::replica::{DecodedFrame, ReplicaClient, ReplicaEvent};
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
let expected = DecodedFrame::new(0, argv(&["SET", "k", "v"]));
assert_eq!(client.next_event().transpose()?, Some(ReplicaEvent::Frame(expected)));Ping(FeedPosition)
In-stream heartbeat: the primary’s tail at send time — its feed
generation (the REPL.TOKEN / REPL.WAIT gen truth; 0 = the
primary spoke the legacy one-number heartbeat, “unknown”) and its
next_offset. Lets the replica compute lag (applied vs primary)
and judge link liveness. Occupies no offset space.
use kevy_replicate::feed::FeedPosition;
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
let mut client = ReplicaClient::connect(addr, "replica-a", 100)?;
let Some(ReplicaEvent::Ping(tail)) = client.next_event().transpose()? else { panic!() };
assert_eq!(tail.offset - client.expected_offset(), 20); // frames behind the primarySnapshotBegin
Snapshot ship begin marker (+SNAPSHOT\r\n).
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
assert_eq!(client.next_event().transpose()?, Some(ReplicaEvent::SnapshotBegin));SnapshotChunk(Vec<u8>)
One snapshot chunk’s payload bytes (RESP bulk string body).
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
use kevy_replicate::wire;
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
client.next_event(); // SnapshotBegin
let chunk = ReplicaEvent::SnapshotChunk(b"part-1".to_vec());
assert_eq!(client.next_event().transpose()?, Some(chunk));SnapshotEnd
Snapshot ship end marker carrying the offset the next live frame will have.
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
use kevy_replicate::wire;
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
client.next_event(); // SnapshotBegin
let end = client.next_event().transpose()?;
assert_eq!(end, Some(ReplicaEvent::SnapshotEnd { ack_offset: 57 }));Fields
ack_offset: u64The offset the primary’s next_offset was at when the
snapshot started. After this event, ReplicaClient::expected_offset
equals this value.
use kevy_replicate::replica::{ReplicaClient, ReplicaEvent};
use kevy_replicate::wire;
let mut client = ReplicaClient::connect(addr, "replica-a", 0)?;
client.next_event(); // SnapshotBegin
let Some(ReplicaEvent::SnapshotEnd { ack_offset }) = client.next_event().transpose()? else {
panic!("expected the end marker")
};
assert_eq!(client.expected_offset(), ack_offset); // the next live frame is 57