Fixes shutdown deadlock in websocket client #1221
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Reviewers
r? @stripe/developer-products
Summary
This change solves a deadlock that can happen in
stripe listen
when the underlying websocket connection closes or is reconnecting while the websocket client is attempting to send a message. The deadlock happens when thewritePump
has a message to send:runs into an error trying to send the message because the connection has been closed for one reason or another:
and attempts to re-queue the message it was going to process:
c.send
is unbuffered, and only read from in this select. Sending messages toc.send
in the same block that processes reads fromc.send
will always deadlock, as message sending to unbuffered channels blocks until the message is read.This PR fixes that deadlock by making
c.send
a buffered channel, allowing the re-queueing behavior we're looking for.This condition is not all that common, but given
stripe listen
tries to reconnect every once in a while this could happen more often than you'd think in a busystripe listen
session.This change comes with a unit test meant to provoke the regression to verify it remains fixed. That test was a little challenging to write (I'm still learning how to do these well), and to support the new test case I added some synchronization primitives in the websocket client to make it easier to monkey with the client from the test case.