File Coverage

blib/lib/Async/Redis/Error/Redis.pm
Criterion Covered Total %
statement 27 33 81.8
branch 3 6 50.0
condition 7 20 35.0
subroutine 13 16 81.2
pod 12 12 100.0
total 62 87 71.2


line stmt bran cond sub pod time code
1             package Async::Redis::Error::Redis;
2              
3 69     69   973 use strict;
  69         162  
  69         4210  
4 69     69   352 use warnings;
  69         139  
  69         3541  
5 69     69   1269 use 5.018;
  69         265  
6              
7             our $VERSION = '0.001';
8              
9 69     69   488 use parent 'Async::Redis::Error';
  69         155  
  69         556  
10              
11 3     3 1 384 sub type { shift->{type} }
12              
13             # Parse error type from Redis error message
14             # Redis errors are formatted as: "ERRORTYPE message text"
15             sub from_message {
16 2     2 1 4936 my ($class, $message) = @_;
17              
18 2         5 my $type = 'ERR'; # default
19 2 50       16 if ($message =~ /^([A-Z]+)\s/) {
20 2         7 $type = $1;
21             }
22              
23 2         11 return $class->new(
24             message => $message,
25             type => $type,
26             );
27             }
28              
29             # Predicate methods for common error types
30 7   50 7 1 71 sub is_wrongtype { uc(shift->{type} // '') eq 'WRONGTYPE' }
31 7   50 7 1 1691 sub is_oom { uc(shift->{type} // '') eq 'OOM' }
32 7   50 7 1 1852 sub is_busy { uc(shift->{type} // '') eq 'BUSY' }
33 6   50 6 1 1932 sub is_noscript { uc(shift->{type} // '') eq 'NOSCRIPT' }
34 6   50 6 1 1852 sub is_readonly { uc(shift->{type} // '') eq 'READONLY' }
35 7   50 7 1 1659 sub is_loading { uc(shift->{type} // '') eq 'LOADING' }
36 0   0 0 1 0 sub is_noauth { uc(shift->{type} // '') eq 'NOAUTH' }
37 0   0 0 1 0 sub is_noperm { uc(shift->{type} // '') eq 'NOPERM' }
38              
39             # Fatal errors should not be retried
40             sub is_fatal {
41 7     7 1 1791 my $self = shift;
42 7   50     20 my $type = uc($self->{type} // '');
43              
44             # These are deterministic failures - retrying won't help
45 7 100       46 return 1 if $type =~ /^(WRONGTYPE|OOM|NOSCRIPT|NOAUTH|NOPERM|ERR)$/;
46              
47 3         12 return 0;
48             }
49              
50             # Transient errors may succeed on retry
51             sub is_transient {
52 0     0 1   my $self = shift;
53 0   0       my $type = uc($self->{type} // '');
54              
55             # These may succeed if retried after a delay
56 0 0         return 1 if $type =~ /^(BUSY|LOADING|READONLY|CLUSTERDOWN)$/;
57              
58 0           return 0;
59             }
60              
61             1;
62              
63             __END__