File Coverage

blib/lib/Mojo/Redis.pm
Criterion Covered Total %
statement 53 55 96.3
branch 12 18 66.6
condition 18 23 78.2
subroutine 17 18 94.4
pod 4 4 100.0
total 104 118 88.1


line stmt bran cond sub pod time code
1             package Mojo::Redis;
2 18     18   4055965 use Mojo::Base 'Mojo::EventEmitter';
  18         230  
  18         140  
3              
4 18     18   35845 use Mojo::URL;
  18         125481  
  18         137  
5 18     18   8468 use Mojo::Redis::Connection;
  18         66  
  18         139  
6 18     18   8825 use Mojo::Redis::Cache;
  18         67  
  18         121  
7 18     18   8658 use Mojo::Redis::Cursor;
  18         43  
  18         145  
8 18     18   11335 use Mojo::Redis::Database;
  18         55  
  18         118  
9 18     18   9017 use Mojo::Redis::PubSub;
  18         48  
  18         119  
10 18     18   683 use Scalar::Util 'blessed';
  18         39  
  18         17580  
11              
12             our $VERSION = '3.28';
13              
14             $ENV{MOJO_REDIS_URL} ||= 'redis://localhost:6379';
15              
16             has encoding => 'UTF-8';
17             has max_connections => 5;
18              
19             has protocol_class => do {
20             my $class = $ENV{MOJO_REDIS_PROTOCOL};
21             $class ||= eval { require Protocol::Redis::XS; Protocol::Redis::XS->VERSION('0.06'); 'Protocol::Redis::XS' };
22             $class ||= 'Protocol::Redis::Faster';
23             eval "require $class; 1" or die $@;
24             $class;
25             };
26              
27             has pubsub => sub {
28             my $self = shift;
29             my $pubsub = Mojo::Redis::PubSub->new(redis => $self);
30             Scalar::Util::weaken($pubsub->{redis});
31             return $pubsub;
32             };
33              
34             has url => sub { Mojo::URL->new($ENV{MOJO_REDIS_URL}) };
35              
36 1     1 1 17 sub cache { Mojo::Redis::Cache->new(redis => shift, @_) }
37 0 0   0 1 0 sub cursor { Mojo::Redis::Cursor->new(redis => shift, command => [@_ ? @_ : (scan => 0)]) }
38 12     12 1 6521 sub db { Mojo::Redis::Database->new(redis => shift) }
39              
40             sub new {
41 12     12 1 10192 my $class = shift;
42 12 100 100     119 return $class->SUPER::new(@_) unless @_ % 2 and ref $_[0] ne 'HASH';
43 7         18 my $url = shift;
44 7 100 66     78 $url = Mojo::URL->new($url) unless blessed $url and $url->isa('Mojo::URL');
45 7         1459 return $class->SUPER::new(url => $url, @_);
46             }
47              
48             sub _connection {
49 16     16   71 my ($self, %args) = @_;
50              
51 16   66     110 $args{ioloop} ||= Mojo::IOLoop->singleton;
52 16         154 my $conn = Mojo::Redis::Connection->new(
53             encoding => $self->encoding,
54             protocol => $self->protocol_class->new(api => 1),
55             url => $self->url->clone,
56             %args
57             );
58              
59 16         1603 Scalar::Util::weaken($self);
60 16     5   137 $conn->on(connect => sub { $self->emit(connection => $_[0]) });
  5         80  
61 16         216 $conn;
62             }
63              
64             sub _blocking_connection {
65 5     5   3919 my $self = shift->_fork_safety;
66              
67             # Existing connection
68 5         12 my $conn = $self->{blocking_connection};
69 5 50 66     27 return $conn->encoding($self->encoding) if $conn and $conn->is_connected;
70              
71             # New connection
72 5 100       43 return $self->{blocking_connection} = $self->_connection(ioloop => $conn ? $conn->ioloop : Mojo::IOLoop->new);
73             }
74              
75             sub _dequeue {
76 10     10   85 my $self = shift->_fork_safety;
77              
78             # Exsting connection
79 10 0       19 while (my $conn = shift @{$self->{queue} || []}) { return $conn->encoding($self->encoding) if $conn->is_connected }
  0 100       0  
  10         54  
80              
81             # New connection
82 10         41 return $self->_connection;
83             }
84              
85             sub _enqueue {
86 10     10   27 my ($self, $conn) = @_;
87 10   100     40 my $queue = $self->{queue} ||= [];
88 10 100 100     36 push @$queue, $conn if $conn->is_connected and $conn->url eq $self->url and $conn->ioloop eq Mojo::IOLoop->singleton;
      66        
89 10         2300 shift @$queue while @$queue > $self->max_connections;
90             }
91              
92             sub _fork_safety {
93 15     15   33 my $self = shift;
94 15 50 66     101 delete @$self{qw(blocking_connection pid queue)} unless ($self->{pid} //= $$) eq $$; # Fork-safety
95 15         29 $self;
96             }
97              
98             1;
99              
100             =encoding utf8
101              
102             =head1 NAME
103              
104             Mojo::Redis - Redis driver based on Mojo::IOLoop
105              
106             =head1 SYNOPSIS
107              
108             =head2 Blocking
109              
110             use Mojo::Redis;
111             my $redis = Mojo::Redis->new;
112             $redis->db->set(foo => 42);
113             $redis->db->expire(foo => 600);
114             warn $redis->db->get('foo');
115              
116             =head2 Promises
117              
118             $redis->db->get_p("mykey")->then(sub {
119             print "mykey=$_[0]\n";
120             })->catch(sub {
121             warn "Could not fetch mykey: $_[0]";
122             })->wait;
123              
124             =head2 Pipelining
125              
126             Pipelining is built into the API by sending a lot of commands and then use
127             L to wait for all the responses.
128              
129             Mojo::Promise->all(
130             $db->set_p($key, 10),
131             $db->incrby_p($key, 9),
132             $db->incr_p($key),
133             $db->get_p($key),
134             $db->incr_p($key),
135             $db->get_p($key),
136             )->then(sub {
137             @res = map {@$_} @_;
138             })->wait;
139              
140             =head1 DESCRIPTION
141              
142             L is a Redis driver that use the L, which makes it
143             integrate easily with the L framework.
144              
145             It tries to mimic the same interface as L, L and
146             L, but the methods for talking to the database vary.
147              
148             This module is in no way compatible with the 1.xx version of C
149             and this version also tries to fix a lot of the confusing methods in
150             C related to pubsub.
151              
152             This module is currently EXPERIMENTAL, and bad design decisions will be fixed
153             without warning. Please report at
154             L if you find this module
155             useful, annoying or if you simply find bugs. Feedback can also be sent to
156             C.
157              
158             =head1 EVENTS
159              
160             =head2 connection
161              
162             $cb = $redis->on(connection => sub { my ($redis, $connection) = @_; });
163              
164             Emitted when L connects to the Redis.
165              
166             =head1 ATTRIBUTES
167              
168             =head2 encoding
169              
170             $str = $redis->encoding;
171             $redis = $redis->encoding("UTF-8");
172              
173             The value of this attribute will be passed on to
174             L when a new connection is created. This
175             means that updating this attribute will not change any connection that is
176             in use.
177              
178             Default value is "UTF-8".
179              
180             =head2 max_connections
181              
182             $int = $redis->max_connections;
183             $redis = $redis->max_connections(5);
184              
185             Maximum number of idle database handles to cache for future use, defaults to
186             5. (Default is subject to change)
187              
188             =head2 protocol_class
189              
190             $str = $redis->protocol_class;
191             $redis = $redis->protocol_class("Protocol::Redis::XS");
192              
193             Default to L if the optional module is available and at
194             least version 0.06, or falls back to L.
195              
196             =head2 pubsub
197              
198             $pubsub = $redis->pubsub;
199              
200             Lazy builds an instance of L for this object, instead of
201             returning a new instance like L does.
202              
203             =head2 url
204              
205             $url = $redis->url;
206             $redis = $redis->url(Mojo::URL->new("redis://localhost/3"));
207              
208             Holds an instance of L that describes how to connect to the Redis server.
209              
210             =head1 METHODS
211              
212             =head2 db
213              
214             $db = $redis->db;
215              
216             Returns an instance of L.
217              
218             =head2 cache
219              
220             $cache = $redis->cache(%attrs);
221              
222             Returns an instance of L.
223              
224             =head2 cursor
225              
226             $cursor = $redis->cursor(@command);
227              
228             Returns an instance of L with
229             L set to the arguments passed. See
230             L. for possible commands.
231              
232             =head2 new
233              
234             $redis = Mojo::Redis->new("redis://localhost:6379/1");
235             $redis = Mojo::Redis->new(Mojo::URL->new->host("/tmp/redis.sock"));
236             $redis = Mojo::Redis->new(\%attrs);
237             $redis = Mojo::Redis->new(%attrs);
238              
239             Object constructor. Can coerce a string into a L and set L
240             if present.
241              
242             =head1 AUTHORS
243              
244             Jan Henning Thorsen - C
245              
246             Dan Book - C
247              
248             =head1 COPYRIGHT AND LICENSE
249              
250             Copyright (C) 2018, Jan Henning Thorsen.
251              
252             This program is free software, you can redistribute it and/or modify it under
253             the terms of the Artistic License version 2.0.
254              
255             =cut