File Coverage

blib/lib/Redis/Transaction.pm
Criterion Covered Total %
statement 14 46 30.4
branch 0 20 0.0
condition 0 5 0.0
subroutine 5 9 55.5
pod 2 2 100.0
total 21 82 25.6


line stmt bran cond sub pod time code
1             package Redis::Transaction;
2 7     7   820963 use 5.008005;
  7         58  
3 7     7   37 use strict;
  7         14  
  7         143  
4 7     7   57 use warnings;
  7         13  
  7         342  
5              
6             our $VERSION = "0.02";
7              
8 7     7   46 use Carp;
  7         14  
  7         444  
9              
10 7     7   49 use Exporter 'import';
  7         12  
  7         2785  
11             our @EXPORT_OK = qw/multi_exec watch_multi_exec/;
12              
13             sub multi_exec {
14 0     0 1   my ($redis, $retry_count, $code) = @_;
15 0     0     return watch_multi_exec($redis, [], $retry_count, sub {}, $code);
16             }
17              
18             sub watch_multi_exec {
19 0     0 1   my ($redis, $watch_keys, $retry_count, $before, $code) = @_;
20 0           my $err;
21             my @ret_before;
22 0           for (1..$retry_count) {
23 0           eval {
24 0 0         $redis->watch(@$watch_keys) if @$watch_keys;
25 0 0         @ret_before = $before->($redis) if $before;
26             };
27 0 0         if ($err = $@) {
28             # clear IN-WATCHING flag, enable reconnect.
29 0           eval {
30 0           $redis->unwatch;
31             };
32 0 0         $redis->connect if $@;
33              
34             # we can retry $code because the redis has not executed $code yet.
35 0           next;
36             }
37              
38 0           eval {
39 0     0     $redis->multi(sub {});
40 0           $code->($redis, @ret_before);
41 0           $redis->wait_all_responses; # force enqueue all commands
42             };
43 0 0         if ($err = $@) {
44             # clear IN-TRANSACTION flag, enable reconnect.
45 0           eval {
46 0           $redis->discard;
47             };
48 0 0         $redis->connect if $@;
49              
50             # we can retry $code because the redis has not executed $code yet.
51 0           next;
52             }
53              
54 0           my $ret = eval {
55 0           $redis->exec;
56             };
57 0 0         if ($err = $@) {
58 0 0         if ($err =~ /\[exec\] ERR EXEC without MULTI/i) {
59             # perl-redis triggers reconnect
60 0           next;
61             }
62              
63             # clear IN-TRANSACTION flag, enable reconnect.
64 0           $redis->connect;
65              
66             # other network error.
67             # watch_multi_exec cannot decide if we should reconnect
68 0           croak $err;
69             }
70              
71             # retry if someone else changed watching keys.
72 0 0         next unless defined $ret;
73              
74 0 0 0       return (wantarray && ref $ret eq 'ARRAY') ? @$ret : $ret;
75             }
76              
77 0   0       croak ($err || 'failed to retry');
78             }
79              
80             1;
81             __END__