-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Elasticache: Abort incomplete pipelines and transactions upon reconnect #1084
Conversation
Elasticache severs the connection immediately after it returns a READONLY error. This can sometimes leave queued up pipelined commands in an inconsistent state when the connection is reestablished. For example, if a pipeline has 6 commands and the second one generates a READONLY error, Elasticache will only return results for the first two before severing the connection. Upon reconnect, the pipeline still thinks it has 6 commands to send but the commandQueue has only 4. This fix will detect any pipeline command sets that only had a partial response before connection loss, and abort them. This Elasticache behavior also affects transactions. If reconnectOnError returns 2, some transaction fragments may end up in the offlineQueue. This fix will check the offlineQueue for any such transaction fragments and abort them, so that we don't send mismatched multi/exec to redis upon reconnection. - Introduced piplineIndex property on pipelined commands to allow for later cleanup - Added a routine to event_handler that aborts any pipelined commands inside commandQueue and offlineQueue that were interrupted in the middle of the pipeline - Added a routine to event_handler that removes any transaction fragments from the offline queue - Introduced inTransaction property on commands to simplify pipeline logic - Added a flags param to mock_server to allow the Elasticache disconnect behavior to be simulated - Added a reconnect_on_error test case for transactions - Added some test cases testing for correct handling of this unique elasticache behavior - Added unit tests to validate inTransaction and pipelineIndex setting Fixes redis#965
3505d83
to
aa5fe68
Compare
// the connection close and those pipelined commands must be aborted. For | ||
// example, if the queue looks like this: [2, 3, 4, 0, 1, 2] then after | ||
// aborting and purging we'll have a queue that looks like this: [0, 1, 2] | ||
function abortIncompletePipelines(commandQueue: Deque<ICommandItem>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do feel like this approach is treating the downstream symptoms rather than the root cause of the problem. The tradeoff is that it isolates connection handling cleanup stuff inside event_handler so that transaction.ts and pipeline.ts can be more decoupled from reconnection behaviors.
I'm open to other ways of approaching this.
Awesome! Merged 🍻 |
🎉 This PR is included in version 4.16.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
## [4.16.1](redis/ioredis@v4.16.0...v4.16.1) (2020-03-28) ### Bug Fixes * abort incomplete pipelines upon reconnect ([#1084](redis/ioredis#1084)) ([0013991](redis/ioredis@0013991)), closes [#965](redis/ioredis#965)
Elasticache severs the connection immediately after it returns a
READONLY error. This can sometimes leave queued up pipelined commands
in an inconsistent state when the connection is reestablished. For
example, if a pipeline has 6 commands and the second one generates a
READONLY error, Elasticache will only return results for the first two
before severing the connection. Upon reconnect, the pipeline still
thinks it has 6 commands to send but the commandQueue has only 4. This
fix will detect any pipeline command sets that only had a partial
response before connection loss, and abort them.
This Elasticache behavior also affects transactions. If reconnectOnError
returns 2, some transaction fragments may end up in the offlineQueue.
This fix will check the offlineQueue for any such transaction fragments
and abort them, so that we don't send mismatched multi/exec to redis
upon reconnection.
cleanup
commandQueue and offlineQueue that were interrupted in the middle of the
pipeline
fragments from the offline queue
behavior to be simulated
behavior
Fixes #965
You can simulate this Elasticache disconnect behavior on a local redis instance by modifying the source like so:
(Thanks for the idea @luin)