Skip to content
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

Bugfix #41302 - Add an explicit reconnect for failed Redis connections #41502

Closed
wants to merge 4 commits into from

Conversation

xrobau
Copy link
Contributor

@xrobau xrobau commented Mar 16, 2022

When a \Redis connection has a socket/connection error, there's no
reliable way to re-establish the connection. This adds a simple
public 'shouldRestart' bool (based on the existing Queue\Worker
'stopWorkerIfLostConnection' code) to the Redis Connection, which
is checked in RedisManager and recreated if needed there.

Signed-Off-By: Rob Thomas xrobau@gmail.com

xrobau added 2 commits March 16, 2022 01:30
…nections

When a \Redis connection has a socket/connection error, there's no
reliable way to re-establish the connection. This adds a simple
public 'shouldRestart' bool (based on the existing Queue\Worker
'stopWorkerIfLostConnection' code) to the Redis Connection, which
is checked in RedisManager and recreated if needed there.

Signed-Off-By: Rob Thomas <xrobau@gmail.com>
return $this->connections[$name];
}
// Unset and destroy the Connection object to ensure it's cleaned up.
unset($this->connections[$name]);
Copy link
Contributor Author

@xrobau xrobau Mar 16, 2022

Choose a reason for hiding this comment

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

Note the unset is here to make sure that the isset always returns false from now on, even if the configure below fails.

@driesvints
Copy link
Member

Thanks @xrobau

@taylorotwell
Copy link
Member

I don't understand why we would return an empty array on failure. Wouldn't we just want to rethrow the exception and let it be logged, etc?

@xrobau
Copy link
Contributor Author

xrobau commented Mar 16, 2022

Updated PR @taylorotwell - I was returning an empty array because the noise was irritating to me, but that's not going to help anyone else 8)

$result = $this->client->{$method}(...$parameters);
try {
$result = $this->client->{$method}(...$parameters);
} catch (\RedisException $e) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you import all classes?

Copy link
Contributor Author

@xrobau xrobau Mar 17, 2022

Choose a reason for hiding this comment

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

Edit: Ah, you were asking for this to be used at the top, rather than explicitly quoted as a root namespace in the exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@driesvints this may be resolved simply by ALWAYS reconnecting redis here, rather than only on one specific edge case. Waiting for feedback below, which would simplify this to simply removing the if.

https://github.com/laravel/framework/blob/9.x/src/Illuminate/Redis/Connections/PhpRedisConnection.php#L534

src/Illuminate/Redis/RedisManager.php Outdated Show resolved Hide resolved
@taylorotwell
Copy link
Member

taylorotwell commented Mar 17, 2022

Did you examine the code for PhpRedisConnection? It already has reconnection logic within its command method. Why can that not be used / modified?

Furthermore, RedisException is specific to the phpredis C extension - not Predis. So, these changes don't make sense in the base Connection class. They are phpredis specific.

image

@taylorotwell taylorotwell marked this pull request as draft March 17, 2022 20:34
@xrobau
Copy link
Contributor Author

xrobau commented Mar 17, 2022

Screenshot above references https://github.com/laravel/framework/blob/9.x/src/Illuminate/Redis/Connections/PhpRedisConnection.php#L533 for anyone with visual issues.

@taylorotwell - What would you prefer? That code is currently ONLY catching 'has gone away', which appears to be triggered by a controlled shutdown of Redis. The error that I'm attempting to fix is when an UNCONTROLLED shutdown happens, or a network issue.

Anecdotally, I've never had any exception thrown by Phpredis that is recoverable at all. Was there any reason that only one edge case is handled?

xrobau added a commit to xrobau/framework that referenced this pull request Mar 17, 2022
This is an alternative option to PR laravel#41502, and adds a match
for 'socket' ("socket error when (reading|writing)") to trigger
a reconnection.

I am not sure if this is valid in other languages, too.

My personal preference would be to remove the entire if and
ALWAYS reconnect on any Exception

Signed-Off-By: Rob Thomas xrobau@gmail.com
@xrobau xrobau mentioned this pull request Mar 17, 2022
@xrobau
Copy link
Contributor Author

xrobau commented Mar 17, 2022

Alternative PR #41546 - as I mention in the PR, I don't think this is suitable, and would prefer to remove the if totally.

taylorotwell pushed a commit that referenced this pull request Mar 18, 2022
* Bugfix #41302 - Alternative

This is an alternative option to PR #41502, and adds a match
for 'socket' ("socket error when (reading|writing)") to trigger
a reconnection.

I am not sure if this is valid in other languages, too.

My personal preference would be to remove the entire if and
ALWAYS reconnect on any Exception

Signed-Off-By: Rob Thomas xrobau@gmail.com

* Fix typo (used vim instead of my usual IDE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Redis Connection does not reconnect when failed, causing Queue Workers to loop
3 participants