Rhino Service BusManaging Timeouts
I was first introduced to the notion of time as an explicit concept in Udi’s writing. The notion of being able to send a message in the future was, like most of the things that Udi talks about, simple in terms of implementation, but profound in conceptual terms.
Rhino Service Bus supports this explicitly by specifying a time in which a message will be received. The implementation for that is quite interesting, I think.
Again, we are making use of a subqueue to minimize the additional requirements that RSB has. So when we send a message to the RSB with a delay in it, we move it to the timeout subquque are record that fact internally. We have a timer going off every second that check for expiry of the messages and dispatch them when their time arrives. If the system crash at any point, all the timeouts are stored in the subqueue, and on startup, we are going to read the timeout messages and reconstruct our internal representation of them.
The API is quite simple:
1: bus.DelaySend(bus.Endpoint,2: DateTime.Now.AddMilliseconds(250),3: msg);
We might need to make some changes to support extremely large queues and extremely long duration for delayed messages, but for now, it is doing quite well.
More posts in "Rhino Service Bus" series:
- (08 Aug 2009) DHT Saga Sate Persisters Options
- (21 Jan 2009) Concurrency Violations are Business Logic
- (19 Jan 2009) Concurrency in a distributed world
- (16 Jan 2009) Saga and State
- (15 Jan 2009) Field Level Security
- (14 Jan 2009) Understanding a Distributed System
- (14 Jan 2009) The Starbucks example
- (14 Jan 2009) Locality and Independence
- (14 Jan 2009) Managing Timeouts
Ayende, can you elaborate a bit more about this feature?
performance. Will it degrade if large number of future messages is queued?
what is the timer accuracy? 1 second?
what about long durations - days ... months? Is it a problem?
could this feature be used to implement a retry strategy for failed messages (failing messages will be rescheduled for later retry)?
We currently keep about 64 bytes in memory for each future message. This means that for a million future messages, we are going to consume about 60 MB.
That is what I referred to as potential limitation. Although I don't really consider that as a true limitation because I don't really expect to have that many future messages on a single endpoint.
Timer accuracy is one second, yes. If you can think of anything that would make require lower granularity, I would like to hear about it.
Duration of days / months should not be a problem, although I admit that I don't have an integration test that waits for 3 days :-)
Yes, it could be implemented as retry strategy, although RSB already contains a retry strategy for messages by rolling back the transaction and retrying immediately.
Sounds good. What made you chose a 1-second polling timer over the concept of calculating the delay and having an event fired at that time, though?
Complexity vs. simplicity