Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Redis CPAN distribution.

Report information
The Basics
Id: 64473
Status: resolved
Priority: 0/
Queue: Redis

People
Owner: melo [...] cpan.org
Requestors: brian [...] omniti.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Feature: auto-reconnect/retry on timeout/error
Date: Tue, 4 Jan 2011 16:16:16 -0500
To: bug-redis [...] rt.cpan.org
From: Brian Dunavant <brian [...] omniti.com>
Problem: Redis is distributed with a timeout of 300 seconds in the default config. For obvious reasons there are disadvantages of turning that off. However, putting error handling to reconnect everywhere in your system that you use redis is also a bit annoying. Having redis handle attempting a reconnection automatically would make this less painful as now I only have to deal with actual errors and not that I timed out or we just had a simple internet hiccup. Solution: Have a flag to let Redis handle attempting to reconnect once if there is an issue by passing auto_reconnect_and_retry => 1 in the constructor. Code: Replace sub new() with the following (moves connection into a private function) : sub new { my $class = shift; my $self = {@_}; $self->{debug} ||= $ENV{REDIS_DEBUG}; bless($self, $class); $self->__connect() || die $!; $self; } ------- Modify the following line in AUTOLOAD from: my $result = <$sock> || die "can't read socket: $!"; To: my $result = <$sock> || $self->__reconnect_and_retry($send) || die "can't read socket: $!"; -------- Add the following two functions: sub __connect { my $self = shift; warn ">> Attempting to connect",$/ if $self->{debug}; $self->{sock} = IO::Socket::INET->new( PeerAddr => $self->{server} || $ENV{REDIS_SERVER} || '127.0.0.1:6379', Proto => 'tcp', ); $self->{sock}; } sub __reconnect_and_retry { my ($self,$send) = @_; return undef unless $self->{auto_reconnect_and_retry}; warn ">> Attempting to Reconnect",$/ if $self->{debug}; $self->__connect() || die "While trying to reconnect: $!"; warn ">> Attempting to Resend command: $send",$/ if $self->{debug}; my $sock = $self->{sock}; print $sock $send; warn "<< Attempting to reread result",$/ if $self->{debug}; my $result = <$sock> || die "can't read socket: $!"; warn "<< Returning refetched result",$/ if $self->{debug}; return $result; } ========= After the fix (which is in my BrianRedis.pm module) assuming you have a key "blah" with value "0" the following should now work. ; perl -I/home/brian -MBrianRedis -e '$r = BrianRedis->new( autoreconnect => 1, debug => 1 ); sleep 400; print "".$r->get("blah")."\n";' Show quoted text
>> Attempting to connect
## get $VAR1 = 'blah'; Show quoted text
>> GET blah >> Attempting to Reconnect >> Attempting to connect >> Attempting to Resend command: GET blah
<< Attempting to reread result << Returning refetched result << $1 << $VAR1 = '0'; 0
Hi, I'll add automatic reconnect in a near future version of Redis but its more complicated than that. I want to make sure it deals properly with MULTI/EXEC which is something that I want to implement too. Also there are a lot of scenarios that we need to deal with. For example, what to do if the disconnected is detected: 1. before sending the command: easiest case for non-MULTI/EXEC scenario - reconnect and try again - need exponential back-off though; 2. after sending the command, while waiting or reading the response: we can reconnect but we cannot resend the command because the action would be executed twice - what to do here? When inside a MULTI/EXEC transaction, you have: * before the EXEC: reconnect and resend all *write* ops? * after the EXEC: we cannot resend it. Thoughs? (I've also sent this message to the redis ML) Thanks,
Hi, reconnect option added. See: https://github.com/melo/perl-redis/pull/6 https://github.com/melo/perl-redis/commit/7e8f33330f2 for the code. Released tomorrow. Thanks, -- Hi, how are you?