File Coverage

blib/lib/EV/Redis.pm
Criterion Covered Total %
statement 55 62 88.7
branch 24 60 40.0
condition 4 16 25.0
subroutine 10 11 90.9
pod 1 1 100.0
total 94 150 62.6


line stmt bran cond sub pod time code
1             package EV::Redis;
2 24     24   5206683 use strict;
  24         43  
  24         665  
3 24     24   94 use warnings;
  24         42  
  24         1286  
4              
5 24     24   97 use Carp ();
  24         39  
  24         271  
6 24     24   648 use EV;
  24         2188  
  24         563  
7              
8             BEGIN {
9 24     24   78 use XSLoader;
  24         70  
  24         999  
10 24     24   86 our $VERSION = '0.11';
11 24         31370 XSLoader::load __PACKAGE__, $VERSION;
12             }
13              
14             sub new {
15 6     6 1 360293 my ($class, %args) = @_;
16              
17             Carp::croak("Cannot specify both 'host' and 'path'")
18 6 0 33     25 if exists $args{host} && exists $args{path};
19             Carp::croak("Cannot specify both 'prefer_ipv4' and 'prefer_ipv6'")
20 6 0 33     16 if $args{prefer_ipv4} && $args{prefer_ipv6};
21              
22 6   33     51 my $loop = $args{loop} // EV::default_loop;
23 6         110 my $self = $class->_new($loop);
24              
25 6   33 0   56 $self->on_error($args{on_error} // sub { die @_ });
  0         0  
26 6 50       17 $self->on_connect($args{on_connect}) if exists $args{on_connect};
27 6 50       15 $self->on_disconnect($args{on_disconnect}) if exists $args{on_disconnect};
28 6 50       22 $self->on_push($args{on_push}) if exists $args{on_push};
29 6 50       16 $self->connect_timeout($args{connect_timeout}) if defined $args{connect_timeout};
30 6 50       16 $self->command_timeout($args{command_timeout}) if defined $args{command_timeout};
31 6 50       13 $self->max_pending($args{max_pending}) if defined $args{max_pending};
32 6 50       14 $self->waiting_timeout($args{waiting_timeout}) if defined $args{waiting_timeout};
33 6 50       12 $self->resume_waiting_on_reconnect($args{resume_waiting_on_reconnect}) if defined $args{resume_waiting_on_reconnect};
34 6 50       11 $self->priority($args{priority}) if defined $args{priority};
35 6 50       11 $self->keepalive($args{keepalive}) if defined $args{keepalive};
36 6 50       13 $self->prefer_ipv4($args{prefer_ipv4}) if exists $args{prefer_ipv4};
37 6 50       11 $self->prefer_ipv6($args{prefer_ipv6}) if exists $args{prefer_ipv6};
38 6 50       13 $self->source_addr($args{source_addr}) if defined $args{source_addr};
39 6 50       12 $self->tcp_user_timeout($args{tcp_user_timeout}) if defined $args{tcp_user_timeout};
40 6 50       19 $self->cloexec($args{cloexec}) if exists $args{cloexec};
41 6 50       13 $self->reuseaddr($args{reuseaddr}) if exists $args{reuseaddr};
42              
43             # Configure reconnect if specified
44 6 50       17 if ($args{reconnect}) {
45             $self->reconnect(
46             1,
47             $args{reconnect_delay} // 1000,
48 0   0     0 $args{max_reconnect_attempts} // 0
      0        
49             );
50             }
51              
52             # Configure TLS if specified (must be done before connect)
53 6 100       15 if ($args{tls}) {
54 1 50       11 Carp::croak("TLS support not compiled in; rebuild with EV_REDIS_SSL=1")
55             unless $self->has_ssl;
56             Carp::croak("TLS requires 'host' parameter (not 'path')")
57 1 50       189 if exists $args{path};
58             $self->_setup_ssl_context(
59             $args{tls_ca}, $args{tls_capath}, $args{tls_cert}, $args{tls_key},
60             $args{tls_server_name},
61 0 0       0 exists $args{tls_verify} ? ($args{tls_verify} ? 1 : 0) : 1,
    0          
62             );
63             }
64              
65 5 50       31 if (exists $args{host}) {
    50          
66 0 0       0 Carp::croak("'host' must be a defined string") unless defined $args{host};
67             defined $args{port}
68             ? $self->connect($args{host}, $args{port})
69 0 0       0 : $self->connect($args{host});
70             }
71             elsif (exists $args{path}) {
72 0 0       0 Carp::croak("'path' must be a defined string") unless defined $args{path};
73 0         0 $self->connect_unix($args{path});
74             }
75              
76 5         16 $self;
77             }
78              
79             our $AUTOLOAD;
80              
81             sub AUTOLOAD {
82 1     1   533 (my $method = $AUTOLOAD) =~ s/.*:://;
83 1 50       4 return if $method eq 'DESTROY';
84              
85             my $sub = sub {
86 1     1   1 my $self = shift;
87 1         13 $self->command($method, @_);
88 1         4 };
89              
90 24     24   156 no strict 'refs';
  24         31  
  24         2907  
91 1         18 *$method = $sub;
92 1         3 goto $sub;
93             }
94              
95             1;
96              
97             =head1 NAME
98              
99             EV::Redis - Asynchronous redis client using hiredis and EV
100              
101             =head1 SYNOPSIS
102              
103             use EV::Redis;
104            
105             my $redis = EV::Redis->new;
106             $redis->connect('127.0.0.1');
107            
108             # or
109             my $redis = EV::Redis->new( host => '127.0.0.1' );
110            
111             # command
112             $redis->set('foo' => 'bar', sub {
113             my ($res, $err) = @_;
114            
115             print $res; # OK
116            
117             $redis->get('foo', sub {
118             my ($res, $err) = @_;
119            
120             print $res; # bar
121            
122             $redis->disconnect;
123             });
124             });
125            
126             # start main loop
127             EV::run;
128              
129             =head1 DESCRIPTION
130              
131             EV::Redis is a fork of L by Daisuke Murase (typester),
132             extended with reconnection, flow control, TLS, and RESP3 support. It is a
133             drop-in replacement: the API is fully backward-compatible with EV::Hiredis.
134              
135             This is an asynchronous client for Redis using hiredis and L as backend.
136             It connects to L with C-level interface so that it runs faster.
137              
138             =head1 ANYEVENT INTEGRATION
139              
140             L has a support for EV as its one of backends, so L can be used in your AnyEvent applications seamlessly.
141              
142             =head1 NO UTF-8 SUPPORT
143              
144             Unlike other redis modules, this module doesn't support utf-8 string.
145              
146             This module handle all variables as bytes. You should encode your utf-8 string before passing commands like following:
147              
148             use Encode;
149            
150             # set $val
151             $redis->set(foo => encode_utf8 $val, sub { ... });
152            
153             # get $val
154             $redis->get(foo, sub {
155             my $val = decode_utf8 $_[0];
156             });
157              
158             =head1 METHODS
159              
160             =head2 new(%options);
161              
162             Create new L instance.
163              
164             Available C<%options> are:
165              
166             =over
167              
168             =item * host => 'Str'
169              
170             =item * port => 'Int'
171              
172             Hostname and port number of redis-server to connect. Mutually exclusive with C.
173              
174             =item * path => 'Str'
175              
176             UNIX socket path to connect. Mutually exclusive with C.
177              
178             =item * on_error => $cb->($errstr)
179              
180             Error callback will be called when a connection level error occurs.
181             If not provided (or C), a default handler that calls C is
182             installed. To have no error handler, call C<< $obj->on_error(undef) >>
183             after construction.
184              
185             This callback can be set by C<< $obj->on_error($cb) >> method any time.
186              
187             =item * on_connect => $cb->()
188              
189             Connection callback will be called when connection successful and completed to redis server.
190              
191             This callback can be set by C<< $obj->on_connect($cb) >> method any time.
192              
193             =item * on_disconnect => $cb->()
194              
195             Disconnect callback will be called when disconnection occurs (both normal and error cases).
196              
197             This callback can be set by C<< $obj->on_disconnect($cb) >> method any time.
198              
199             =item * on_push => $cb->($reply)
200              
201             RESP3 push callback for server-initiated out-of-band messages (Redis 6.0+).
202             Called with the decoded push message (an array reference). This enables
203             client-side caching invalidation and other server-push features.
204              
205             This callback can be set by C<< $obj->on_push($cb) >> method any time.
206              
207             =item * connect_timeout => $num_of_milliseconds
208              
209             Connection timeout.
210              
211             =item * command_timeout => $num_of_milliseconds
212              
213             Command timeout.
214              
215             =item * max_pending => $num
216              
217             Maximum number of commands sent to Redis concurrently. When this limit is reached,
218             additional commands are queued locally and sent as responses arrive.
219             0 means unlimited (default). Use C to check the local queue size.
220              
221             =item * waiting_timeout => $num_of_milliseconds
222              
223             Maximum time a command can wait in the local queue before being cancelled with
224             "waiting timeout" error. 0 means unlimited (default).
225              
226             =item * resume_waiting_on_reconnect => $bool
227              
228             Controls behavior of waiting queue on disconnect. If false (default), waiting
229             commands are cancelled with error on disconnect. If true, waiting commands are
230             preserved and resumed after successful reconnection.
231              
232             =item * reconnect => $bool
233              
234             Enable automatic reconnection on connection failure or unexpected disconnection.
235             Default is disabled (0).
236              
237             =item * reconnect_delay => $num_of_milliseconds
238              
239             Delay between reconnection attempts. Default is 1000 (1 second).
240              
241             =item * max_reconnect_attempts => $num
242              
243             Maximum number of reconnection attempts. 0 means unlimited. Default is 0.
244             Negative values are treated as 0 (unlimited).
245              
246             =item * priority => $num
247              
248             Priority for the underlying libev IO watchers. Higher priority watchers are
249             invoked before lower priority ones. Valid range is -2 (lowest) to +2 (highest),
250             with 0 being the default. See L documentation for details on priorities.
251              
252             =item * keepalive => $seconds
253              
254             Enable TCP keepalive with the specified interval in seconds. When enabled,
255             the OS will periodically send probes on idle connections to detect dead peers.
256             0 means disabled (default). Recommended for long-lived connections behind
257             NAT gateways or firewalls.
258              
259             =item * prefer_ipv4 => $bool
260              
261             Prefer IPv4 addresses when resolving hostnames. Mutually exclusive with
262             C.
263              
264             =item * prefer_ipv6 => $bool
265              
266             Prefer IPv6 addresses when resolving hostnames. Mutually exclusive with
267             C.
268              
269             =item * source_addr => 'Str'
270              
271             Local address to bind the outbound connection to. Useful on multi-homed
272             servers to select a specific network interface.
273              
274             =item * tcp_user_timeout => $num_of_milliseconds
275              
276             Set the TCP_USER_TIMEOUT socket option (Linux-specific). Controls how long
277             transmitted data may remain unacknowledged before the connection is dropped.
278             Helps detect dead connections faster on lossy networks.
279              
280             =item * cloexec => $bool
281              
282             Set SOCK_CLOEXEC on the Redis connection socket. Prevents the file descriptor
283             from leaking to child processes after fork/exec. Default is enabled.
284              
285             =item * reuseaddr => $bool
286              
287             Set SO_REUSEADDR on the Redis connection socket. Allows rebinding to an
288             address that is still in TIME_WAIT state. Default is disabled.
289              
290             =item * tls => $bool
291              
292             Enable TLS/SSL encryption for the connection. Requires that the module was
293             built with TLS support (auto-detected at build time, or forced with
294             C). Only valid with C connections, not C.
295              
296             =item * tls_ca => 'Str'
297              
298             Path to CA certificate file for server verification. If not specified,
299             uses the system default CA store.
300              
301             =item * tls_capath => 'Str'
302              
303             Path to a directory containing CA certificate files in OpenSSL-compatible
304             format (hashed filenames). Alternative to C for multiple CA certs.
305              
306             =item * tls_cert => 'Str'
307              
308             Path to client certificate file for mutual TLS authentication. Must be
309             specified together with C.
310              
311             =item * tls_key => 'Str'
312              
313             Path to client private key file. Must be specified together with C.
314              
315             =item * tls_server_name => 'Str'
316              
317             Server name for SNI (Server Name Indication). Optional.
318              
319             =item * tls_verify => $bool
320              
321             Enable or disable TLS peer verification. Default is true (verify).
322             Set to false to accept self-signed certificates (not recommended for
323             production).
324              
325             =item * loop => 'EV::Loop',
326              
327             EV loop for running this instance. Default is C.
328              
329             =back
330              
331             All parameters are optional.
332              
333             If parameters about connection (host&port or path) is not passed, you should call C or C method by hand to connect to redis-server.
334              
335             =head2 connect($hostname [, $port])
336              
337             =head2 connect_unix($path)
338              
339             Connect to a redis-server for C<$hostname:$port> or C<$path>. C<$port>
340             defaults to 6379. Croaks if a connection is already active.
341              
342             =head2 command($commands..., [$cb->($result, $error)])
343              
344             Do a redis command and return its result by callback. Returns C
345             (0) on success or C (-1) if the command could not be enqueued
346             (the error is also delivered via callback, so the return value is rarely needed).
347              
348             $redis->command('get', 'foo', sub {
349             my ($result, $error) = @_;
350              
351             print $result; # value for key 'foo'
352             print $error; # redis error string, undef if no error
353             });
354              
355             If any error is occurred, C<$error> presents the error message and C<$result> is undef.
356             If no error, C<$error> is undef and C<$result> presents response from redis.
357              
358             The callback is optional. Without a callback, the command runs in
359             fire-and-forget mode: the reply from Redis is silently discarded and errors
360             are not reported to Perl code (connection-level errors still trigger
361             C). This is useful for high-volume writes where individual
362             acknowledgement is not needed:
363              
364             $redis->set('counter', 42); # fire-and-forget, no callback
365              
366             NOTE: Alternatively all commands can be called via AUTOLOAD interface,
367             including fire-and-forget:
368              
369             $redis->command('get', 'foo', sub { ... });
370              
371             is equivalent to:
372              
373             $redis->get('foo', sub { ... });
374              
375             B Calling C while not connected will croak with
376             "connection required before calling command", unless automatic reconnection
377             is active (reconnect timer running). In that case, commands are
378             automatically queued and sent after successful reconnection. Queued
379             commands respect C if set.
380              
381             B For C, C, and C, the
382             callback is persistent and receives all messages. For C,
383             C, and C, the confirmation is delivered through
384             the original subscribe callback (this is hiredis behavior). Any callback
385             passed to unsubscribe commands is silently discarded.
386              
387             =head2 disconnect
388              
389             Disconnect from redis-server. Safe to call when already disconnected.
390             Stops any pending reconnect timer, so explicit disconnect prevents automatic
391             reconnection. Triggers the C callback when disconnecting
392             from an active connection. When called while already disconnected, clears
393             any waiting commands (e.g., preserved by C),
394             invoking their callbacks with a "disconnected" error (C
395             does not fire in this case).
396              
397             =head2 is_connected
398              
399             Returns true (1) if a connection context is active (including while the
400             connection is being established), false (0) otherwise.
401              
402             =head2 has_ssl
403              
404             Class method. Returns true (1) if the module was built with TLS support,
405             false (0) otherwise.
406              
407             if (EV::Redis->has_ssl) {
408             # TLS connections are available
409             }
410              
411             =head2 connect_timeout([$ms])
412              
413             Get or set the connection timeout in milliseconds. Pass C<0> to disable.
414             Returns the current value, or undef if never set. Can also be set via
415             constructor.
416              
417             =head2 command_timeout([$ms])
418              
419             Get or set the command timeout in milliseconds. Pass C<0> to disable.
420             Returns the current value, or undef if never set. Can also be set via
421             constructor. When changed while connected, takes effect immediately on
422             the active connection.
423              
424             =head2 on_error([$cb->($errstr)])
425              
426             Set error callback. With a CODE reference argument, replaces the handler
427             and returns the new handler. With C or without arguments, clears
428             the handler and returns undef.
429              
430             B Calling without arguments clears the handler. There is no way to
431             read the current handler without clearing it. This applies to all handler
432             methods (C, C, C, C).
433              
434             =head2 on_connect([$cb->()])
435              
436             Set connect callback. With a CODE reference argument, replaces the handler
437             and returns the new handler. With C or without arguments, clears
438             the handler and returns undef.
439              
440             =head2 on_disconnect([$cb->()])
441              
442             Set disconnect callback, called on both normal and error disconnections.
443             With a CODE reference argument, replaces the handler and returns the new
444             handler. With C or without arguments, clears the handler and
445             returns undef.
446              
447             =head2 on_push([$cb->($reply)])
448              
449             Set RESP3 push callback for server-initiated messages (Redis 6.0+).
450             The callback receives the decoded push message as an array reference.
451             With a CODE reference argument, replaces the handler and returns the new
452             handler. With C or without arguments, clears the handler and
453             returns undef. When changed while connected, takes effect immediately.
454              
455             $redis->on_push(sub {
456             my ($msg) = @_;
457             # $msg is an array ref, e.g. ['invalidate', ['key1', 'key2']]
458             });
459              
460             =head2 reconnect($enable, $delay_ms, $max_attempts)
461              
462             Configure automatic reconnection.
463              
464             $redis->reconnect(1); # enable with defaults (1s delay, unlimited)
465             $redis->reconnect(1, 0); # enable with immediate reconnect
466             $redis->reconnect(1, 2000); # enable with 2 second delay
467             $redis->reconnect(1, 1000, 5); # enable with 1s delay, max 5 attempts
468             $redis->reconnect(0); # disable
469              
470             C<$delay_ms> defaults to 1000 (1 second). 0 means immediate reconnect.
471             C<$max_attempts> defaults to 0 (unlimited).
472              
473             When enabled, the client will automatically attempt to reconnect on connection
474             failure or unexpected disconnection. Intentional C calls will
475             not trigger reconnection.
476              
477             =head2 reconnect_enabled
478              
479             Returns true (1) if automatic reconnection is enabled, false (0) otherwise.
480              
481             =head2 pending_count
482              
483             Returns the number of commands sent to Redis awaiting responses.
484             Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
485             included in this count.
486             When called from inside a command callback, the count includes the
487             current command (it is decremented after the callback returns).
488              
489             =head2 waiting_count
490              
491             Returns the number of commands queued locally (not yet sent to Redis).
492             These are commands that exceeded the C limit.
493              
494             =head2 max_pending($limit)
495              
496             Get or set the maximum number of concurrent commands sent to Redis.
497             Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
498             subject to this limit.
499             0 means unlimited (default). When the limit is reached, additional commands
500             are queued locally and sent as responses arrive.
501              
502             =head2 waiting_timeout($ms)
503              
504             Get or set the maximum time in milliseconds a command can wait in the local queue.
505             Commands exceeding this timeout are cancelled with "waiting timeout" error.
506             0 means unlimited (default). Returns the current value as an integer (0 when unset).
507              
508             =head2 resume_waiting_on_reconnect($bool)
509              
510             Get or set whether waiting commands are preserved on disconnect and resumed
511             after reconnection. Default is false (waiting commands cancelled on disconnect).
512              
513             =head2 priority($priority)
514              
515             Get or set the priority for the underlying libev IO watchers. Higher priority
516             watchers are invoked before lower priority ones when multiple watchers are
517             pending. Valid range is -2 (lowest) to +2 (highest), with 0 being the default.
518             Values outside this range are clamped automatically.
519             Can be changed at any time, including while connected.
520              
521             $redis->priority(1); # higher priority
522             $redis->priority(-1); # lower priority
523             $redis->priority(99); # clamped to 2
524             my $prio = $redis->priority; # get current priority
525              
526             =head2 keepalive($seconds)
527              
528             Get or set the TCP keepalive interval in seconds. When set, the OS sends
529             periodic probes on idle connections to detect dead peers. 0 means disabled
530             (default). When set to a positive value while connected, takes effect
531             immediately. Setting to 0 while connected records the preference for future
532             connections but does not disable keepalives on the current socket.
533              
534             =head2 prefer_ipv4($bool)
535              
536             Get or set IPv4 preference for DNS resolution. Mutually exclusive with
537             C (setting one clears the other). Takes effect on the next
538             connection.
539              
540             =head2 prefer_ipv6($bool)
541              
542             Get or set IPv6 preference for DNS resolution. Mutually exclusive with
543             C (setting one clears the other). Takes effect on the next
544             connection.
545              
546             =head2 source_addr($addr)
547              
548             Get or set the local source address to bind to when connecting. This is
549             useful on multi-homed hosts to control which network interface is used.
550             Pass C to clear. Takes effect on the next TCP connection (has no
551             effect on Unix socket connections).
552              
553             =head2 tcp_user_timeout($ms)
554              
555             Get or set the TCP user timeout in milliseconds. This controls how long
556             transmitted data may remain unacknowledged before the connection is dropped.
557             0 means use the OS default. Takes effect on the next connection.
558              
559             =head2 cloexec($bool)
560              
561             Get or set the close-on-exec flag for the Redis socket. When enabled, the
562             socket is automatically closed in child processes after fork+exec. Enabled
563             by default. Takes effect on the next connection.
564              
565             =head2 reuseaddr($bool)
566              
567             Get or set SO_REUSEADDR on the Redis socket. Allows rebinding to an address
568             still in TIME_WAIT state. Disabled by default. Takes effect on the next
569             connection.
570              
571             =head2 skip_waiting
572              
573             Cancel only waiting (not yet sent) command callbacks. Each callback is invoked
574             with C<(undef, "skipped")>. In-flight commands continue normally.
575              
576             =head2 skip_pending
577              
578             Cancel all pending and waiting command callbacks. Each Perl callback is
579             invoked immediately with C<(undef, "skipped")>. For pending commands,
580             the internal hiredis tracking entry remains until a reply arrives (which
581             is then discarded); no second callback fires.
582              
583             =head2 can($method)
584              
585             Returns code reference if method is available, undef otherwise.
586             Methods installed via AUTOLOAD (Redis commands) will return true after first call.
587              
588             =head1 DESTRUCTION BEHAVIOR
589              
590             When an EV::Redis object is destroyed (goes out of scope or is explicitly
591             undefined) while commands are still pending or waiting, hiredis invokes all
592             pending command callbacks with a disconnect error, and EV::Redis invokes
593             all waiting queue callbacks with C<"disconnected">. This ensures callbacks
594             are not orphaned.
595              
596             For predictable cleanup, explicitly disconnect before destruction:
597              
598             $redis->disconnect; # Clean disconnect, callbacks get error
599             undef $redis; # Safe to destroy
600              
601             Or use skip methods to cancel with a specific error message:
602              
603             $redis->skip_pending; # Invokes callbacks with (undef, "skipped")
604             $redis->skip_waiting;
605             $redis->disconnect;
606             undef $redis;
607              
608             B If your callbacks close over the C<$redis> variable,
609             this creates a reference cycle (C<$redis> -> object -> callback -> C<$redis>)
610             that prevents garbage collection. Break the cycle before the object goes out
611             of scope by clearing callbacks:
612              
613             $redis->on_error(undef);
614             $redis->on_connect(undef);
615             $redis->on_disconnect(undef);
616             $redis->on_push(undef);
617              
618             =head1 BENCHMARKS
619              
620             Measured on Linux with Unix socket connection, 100-byte values, Perl 5.40,
621             Redis 8.x (C):
622              
623             Pipeline SET ~107K ops/sec
624             Pipeline GET ~112K ops/sec
625             Mixed workload ~112K ops/sec
626             Fire-and-forget SET ~655K ops/sec
627             Sequential round-trip ~39K ops/sec (SET+GET pairs)
628              
629             Fire-and-forget mode (no callback) is roughly 6x faster than callback mode
630             due to zero Perl-side overhead per command. Pipeline throughput is bounded
631             by the event loop round-trip, not by hiredis or the network.
632              
633             Flow control (C) has minimal impact at reasonable limits:
634              
635             unlimited ~180K ops/sec
636             max_pending=500 ~186K ops/sec
637             max_pending=100 ~146K ops/sec
638              
639             Run C for full results. Set C and
640             C environment variables to customize.
641              
642             =head1 AUTHOR
643              
644             Daisuke Murase (typester) (original L)
645              
646             vividsnow
647              
648             =head1 COPYRIGHT AND LICENSE
649              
650             Copyright (c) 2013 Daisuke Murase, 2026 vividsnow. All rights reserved.
651              
652             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
653              
654             =cut