OctopusDeploy / Halibut

| Public | A secure communication stack for .NET using JSON-RPC over SSL.
Other
12 stars 44 forks source link

Connection pool async #425

Closed sburmanoctopus closed 1 year ago

sburmanoctopus commented 1 year ago

[sc-53211]

Background

While converting Halibut over to async, we found that the connection manager and connection pool disposes connections while taking new ones. These are async operations, and as such, should be made async.

Results

Related to https://github.com/OctopusDeploy/Issues/issues/8266

Before

Connections were being disposed of synchronously. This is IO that would block any thread while disposable occurred.

After

All methods that result in disposal of a connection within the ConnectionPool now has an async equivalent.

In the ConnectionManager, moving from a lock to a SemaphoreSlim introduced a deadlock. This all revolved around the lock in OnConnectionDisposed. This was focused around access to the activeConnections, so we rearranged the locks to ensure access to activeConnections would not result in a deadlock, and introduced a new lock for general access to the connections in general.

ConnectionManagerFixture

The ConnectionManagerFixture tests had a very convoluted setup, with a mixture of mock and real objects. The real objects did not actually do anything related to the test. This included the MessageExchangeProtocol created by GetProtocol. To show how unimportant these 'real' connections were, there was a bug where the async version of EstablishNewConnection was never configured, and all async tests were working fine with an NSubstitute version. We also needed to interrogate the connection, so this whole area was simplified.

To help identify the deadlocks mentioned above, extra test cases were added to ConnectionManagerFixture that caused the deadlock when using SemaphoreSlim as a pure replacement.

Later

Some more work has to be done in regards to async disposal. But that will be done in the async disposal story.

How to review this PR

RequestCancellationTokens.InProgressRequestCancellationToken was introduced while this was being worked on. I believe this is the correct cancellation token to use (as it is used in the same methods). But please verify that my choice was correct 😁

Quality :heavy_check_mark:

Pre-requisites

shortcut-integration[bot] commented 1 year ago

This pull request has been linked to Shortcut Story #53211: 🎉 🎉 🎉 Make Halibut Support Async RPC Calls 🎉 🎉 🎉.