Skip to content

Refactor provider shutdown and pending flows #240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 13, 2020

Conversation

artemredkin
Copy link
Collaborator

Fixes some edge cases in shutdown and pending states.

Motivation:
There are two issues this PR addresses:

  1. Flaky test, where we are trying to close the client when connection was able to enqueue and get an unexpected error
  2. The fact that provider is created with +1 pending state, while it might not be an error, it makes testing difficult, also might lead to races in shutdown.

Modifications:

  1. HTTP1ConnectionsProvider is no longer created with +1 pending
  2. If we receive close while request is enqueued, it should be failed with a more expected .alreadyShutdown error, since its the only way to get into that state, so test was actually catching the right thing.

Result:
Closes #226
Closes #323

@artemredkin artemredkin requested a review from weissi June 12, 2020 16:31
@artemredkin artemredkin linked an issue Jun 12, 2020 that may be closed by this pull request
@artemredkin artemredkin changed the title Refactor provider shurtdown and pending flows Refactor provider shutdown and pending flows Jun 12, 2020
Copy link
Contributor

@weissi weissi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a great start. I think we can delete some code though.

let provider = HTTP1ConnectionProvider(key: key,
eventLoop: taskEventLoop,
configuration: self.configuration,
pool: self,
backgroundActivityLogger: self.backgroundActivityLogger)
_ = provider.enqueue()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yippie! Could we assert here that the return value is the expected one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great idea, done!

@@ -64,7 +64,7 @@ extension HTTP1ConnectionProvider {
private var openedConnectionsCount: Int = 0

/// Number of enqueued requests, used to track if it is safe to delete the provider.
private var pending: Int = 1
private var pending: Int = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! I left a bunch of stuff like the following comments in the code

        /* BEGIN workaround for #232, this whole block is to be replaced by the commented out line below */
        // not closing the provider here (https://github.com/swift-server/async-http-client/issues/232)
        var state = self.http1ConnectionProvider.state.testsOnly_getInternalState()
        if state.pending == 1, state.waiters.isEmpty, state.leasedConnections.isEmpty, state.openedConnectionsCount == 0 {
            state.pending = 0
            self.http1ConnectionProvider.state.testsOnly_setInternalState(state)
        }
        self.http1ConnectionProvider.closePromise.succeed(())
        /* END workaround for #232 */

and

            // cleanup
            // this cleanup code needs to go and use HTTP1ConnectionProvider's API instead

I believe we can also delete all this code then.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to delete the workaround, some clean up code, and I was able to replace some cleanup with API calls instead of direct state manipulation. Currently there are 3-4 tests that manipulate state directly (they all need the state to be near the limit), do you want me to fix it here or when I get to #232?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, let's fix them in a followup. It's super awesome you could remove the workaround

Copy link
Contributor

@weissi weissi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thank you so much

@@ -148,7 +148,7 @@ extension HTTP1ConnectionProvider {
return .none
}
case .closed:
return .fail(waiter, ProviderClosedError())
return .fail(waiter, HTTPClientError.alreadyShutdown)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@artemredkin from what I can tell, no test noticed that this error changed which probably means no test is getting this error ;). I think we should probably add a test case that tests this condition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filed #244

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specific test is a good idea, yes, though this error was picked up by a test, just not reliably :)

@weissi weissi merged commit bb8c4fa into swift-server:master Jun 13, 2020
@artemredkin artemredkin deleted the provider_pending_close_fix branch June 13, 2020 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants