ObjectCache and RavenDB Changes

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