Skip to content

Subscription Snapshots

Mendel Monteiro-Beckerman edited this page Nov 19, 2020 · 1 revision

Motivation

Subscription snapshots are a feature of Zebus which allows peers to receive a snapshot of the current state of a particular view that they are subscribed to.

Take for example a peer that is a UI (the client) that displays alerts generated and stored by another peer (the server). The client peer would subscribe to an event such as AlertGenerated and display each alert as they are received. This works fine unless the client peer would also wish to display previously generated alerts. One solution to this would be for the client peer to persist all the received messages locally but this comes with a cost as the this peer would have to handle the configuration, consistency and maintenance of the persistence solution. The other downside of this solution is that the volume of data to be persisted is multiplied by the number of client peers.

Another solution would be for the client peer to query the server peer's store shortly before/after subscribing to the AlertGenerated messsage. If the client peer queries the store before subscribing there is a possibility that some messages might be lost, all alerts that are generated between the end of the client peer's query and the reception of the subscription command on the server peer. If the client peer queries the store after subscribing it will have potential duplicate alerts that it will have to reconcile and discard all alerts that are received by the client up until the end of the store query.

As the server peer is the owner of the alert data and also is notified of all subscribed peers it is in a position to be able to send all the previous alerts to the client without suffering from the race conditions mentioned above. The server peer can send a snapshot message that contains the initial state the client peer is subscribed to followed by any new alerts that are generated.

Usage

In order to make use of this functionality in the Zebus all that is necessary is to define a new public class in the server peer which inherits from SubscriptionSnapshotGenerator<TSnapshotMessage, TMessage> where TSnapshotMessage is a message that can contain all the previous alerts and TMessage is AlertGenerated.

A sample implementation would be:

[ProtoContract]
public class AlertsSnapshot : IEvent
{
    [ProtoMember(1)]
    public List<AlertGenerated> Alerts {get; set;}
}

public class AlertSnapshotGenerator : SubscriptionSnapshotGenerator<AlertsSnapshot, AlertGenerated>
{
    public AlertSnapshotGenerator(IBus bus)
        : base(bus)
    {
    }

    protected override AlertsSnapshot GenerateSnapshot(SubscriptionsForType messageSubscription)
    {
        AlertsSnapshot snapshot = GetSnapshotsFromInMemoryStore();
        // The content of the snapshot can be tailored to the subscription details in messageSubscription and any other business requirements.
        return snapshot;
    }
}

On the client side a handler would be added for the AlertsSnapshot message as such:

public class AlertHandler : IMessageHandler<AlertGenerated>, IMessageHandler<AlertsSnapshot>
{
    public void Handle(AlertGenerated alert) { /* handle single alert and update local state */ }
    public void Handle(AlertsSnapshot snapshot) {/* update local state with snapshot data */}
}
Clone this wiki locally