RavenDB Subscriptions & Messaging patterns
RavenDB is a database, not a queue or a service bus. That said, you can make use of RavenDB subscriptions to get a very similar behavior to a service bus. Let’s see how much effort it will take us to implement backend processing using RavenDB only.
We assume that we have commands or messages, that are written to the Commands collection and are handled via a subscription (which may have multiple concurrent workers). In terms of your messaging models, we have:
The CommandBase we have here defines the following infrastructure properties:
- Status – enum [Initial, Processing, Failed, Completed] – default value is Initial
- RetriesCount – int – default value is 3
- Error – string – null by default
We can now define our subscription using the following query:
from Commands as c
where c.RetriesCount > 0 and c.Status != ‘Completed’ and c.’@metadata’.’@refresh’ == null
This query is pretty simple, but it allows me to get all the documents that haven’t exceeded their retry count. The @refresh option allows me to register a command to be executed at a later point in time. See the documentation here, this is a feature that exists specifically to allow you to schedule commands with subscriptions.
In my subscription workers, I can now execute:
The code above is sufficient to get most of the way toward a robust message handling system.
I can easily see what messages are being processing, I can see how long they take, etc. I can see what failed and why. And I can see the history of commands.
That handles scenarios such as error handling and retries, introspection on the state of the system and you can derive from here all the relevant numbers on throughput, capacity, etc.
It isn’t a complete solution, but for very little code, you can take this quite a long way.