-
Notifications
You must be signed in to change notification settings - Fork 708
Description
For both Redis and RabbitMQ, we are putting a "connection" object as a singleton in DI ConnectionMultiplexer in Redis and IConnection in RabbitMQ. These connections are meant to be long-lived as they are expensive to create, so you don't want to make one on every request, and they allow being used concurrently.
The problem is, we establish these connections the first time someone requests them from the DI container. DI is inherently not async because it injects services into constructors, and all of its GetService APIs are not async. This means to establish the connection, we are blocking any thread requesting the connection until it is established. After it is established, the connection remains open (or reconnects under the covers), so threads are no longer blocked on every request once the app starts up.
We should try to think about how to solve this. A few ideas we have floated:
-
Don't directly put the "connection" object in DI, but instead register a "reference to the connection" in DI. Users would request the "reference" service when they needed the connection, and would need to
await reference.GetConnectionAsync()in all the places they need to get the connection from DI. This would allow us to asynchronously establish the connection the first time. Subsequent calls would complete synchronously because the connection is already available. -
Register a sentinel/dummy connection object that throws until the connection is established. Both Redis and RabbitMQ use interfaces, so we could shim the interface with our own object and "swap in" the real connection once it is available.
-
Register a sentinel/dummy connection object that queues up the requests and saves them until the connection is established, and then tries to complete them once the connection is available. This doesn't seem like a realistic approach as there are a lot of methods on these interfaces, and a lot of the methods need an immediate answer.