RavenDb provides a push notifications mechanism, named Changes API, that
allows you to receive messages from a server about events that occurred there. This mechanism makes is extremely simple to create a ChangeMonitor class that can be
used with CacheItemPolicy, in order to expire cache items when something happens on the server (such as a document being updated, and index is modified, etc.)
We’ll start be creating our basic ChangeMonitor class with some boilerplate code:
public class RavenDbChangeMonitor<T> : ChangeMonitor where T : EventArgs { public RavenDbChangeMonitor() { UniqueId = Guid.NewGuid().ToString(); // TODO: Implement monitoring logic InitializationComplete(); } protected override void Dispose(bool disposing) { if (disposing) { // TODO: Stop monitoring } } public override string UniqueId { get; }
After that, we’ll create a private Observer class, which we’ll use to subscribe to the RavenDb changes:
private class Observer : IObserver<T> { private readonly RavenDbChangeMonitor<T> _monitor; public Observer(RavenDbChangeMonitor<T> monitor) { _monitor = monitor; } public void OnNext(T value) { _monitor.OnChanged(value); } public void OnError(Exception error) { } public void OnCompleted() { } }
Now, all we need to do is get the subscriptions, and register our Observer. Let’s add a field and change the constructor of RavenDbChangeMonitor:
private readonly List<IDisposable> _subscribtions = new List<IDisposable>(); public RavenDbChangeMonitor(params IObservableWithTaskT[] observableWithTasks) { UniqueId = Guid.NewGuid().ToString(); // Create our observer var observer = new Observer(this);</pre> // For each observable, we'll subscribe and keep the subscription for later usage foreach (var observableWithTask in observableWithTasks) { var subscription = observableWithTask.Subscribe(observer); _subscribtions.Add(subscription); } InitializationComplete(); }
Lastly, we need to make sure to unsubscribe from the notifications on dispose:
protected override void Dispose(bool disposing) { if (disposing) { foreach (var subscription in _subscribtions) subscription.Dispose(); } }
We can now use our ChangeMonitor with a MemoryCache:
// Register to get notifications on changes of document with Id documents/1 var changes = store.Changes().ForDocument(documents/1); // Create a cache policy, and add our RavenDbChangeMonitor CacheItemPolicy policy = new CacheItemPolicy(); policy.ChangeMonitors.Add(new RavenDbChangeMonitor.RavenDbChangeMonitorDocumentChangeNotification(changes)); // Add entry to cache cache.Set(cacheKey, cacheValue, policy);
You can find the code, along with a working sample, on GitHub https://github.com/saguiitay/RavenDbChangeMonitor