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   5602080 use strict;
  24         50  
  24         786  
3 24     24   108 use warnings;
  24         42  
  24         1448  
4              
5 24     24   108 use Carp ();
  24         71  
  24         393  
6 24     24   710 use EV;
  24         2445  
  24         712  
7              
8             BEGIN {
9 24     24   80 use XSLoader;
  24         72  
  24         1060  
10 24     24   77 our $VERSION = '0.10';
11 24         32111 XSLoader::load __PACKAGE__, $VERSION;
12             }
13              
14             sub new {
15 6     6 1 349496 my ($class, %args) = @_;
16              
17             Carp::croak("Cannot specify both 'host' and 'path'")
18 6 0 33     29 if exists $args{host} && exists $args{path};
19             Carp::croak("Cannot specify both 'prefer_ipv4' and 'prefer_ipv6'")
20 6 0 33     18 if $args{prefer_ipv4} && $args{prefer_ipv6};
21              
22 6   33     46 my $loop = $args{loop} // EV::default_loop;
23 6         93 my $self = $class->_new($loop);
24              
25 6   33 0   51 $self->on_error($args{on_error} // sub { die @_ });
  0         0  
26 6 50       15 $self->on_connect($args{on_connect}) if exists $args{on_connect};
27 6 50       10 $self->on_disconnect($args{on_disconnect}) if exists $args{on_disconnect};
28 6 50       12 $self->on_push($args{on_push}) if exists $args{on_push};
29 6 50       26 $self->connect_timeout($args{connect_timeout}) if defined $args{connect_timeout};
30 6 50       10 $self->command_timeout($args{command_timeout}) if defined $args{command_timeout};
31 6 50       10 $self->max_pending($args{max_pending}) if defined $args{max_pending};
32 6 50       9 $self->waiting_timeout($args{waiting_timeout}) if defined $args{waiting_timeout};
33 6 50       14 $self->resume_waiting_on_reconnect($args{resume_waiting_on_reconnect}) if defined $args{resume_waiting_on_reconnect};
34 6 50       10 $self->priority($args{priority}) if defined $args{priority};
35 6 50       10 $self->keepalive($args{keepalive}) if defined $args{keepalive};
36 6 50       9 $self->prefer_ipv4($args{prefer_ipv4}) if exists $args{prefer_ipv4};
37 6 50       10 $self->prefer_ipv6($args{prefer_ipv6}) if exists $args{prefer_ipv6};
38 6 50       11 $self->source_addr($args{source_addr}) if defined $args{source_addr};
39 6 50       10 $self->tcp_user_timeout($args{tcp_user_timeout}) if defined $args{tcp_user_timeout};
40 6 50       10 $self->cloexec($args{cloexec}) if exists $args{cloexec};
41 6 50       10 $self->reuseaddr($args{reuseaddr}) if exists $args{reuseaddr};
42              
43             # Configure reconnect if specified
44 6 50       20 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       13 if ($args{tls}) {
54 1 50       13 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       170 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       15 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         13 $self;
77             }
78              
79             our $AUTOLOAD;
80              
81             sub AUTOLOAD {
82 1     1   528 (my $method = $AUTOLOAD) =~ s/.*:://;
83 1 50       5 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   171 no strict 'refs';
  24         30  
  24         3299  
91 1         2 *$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. Returns the current value,
414             or undef if not set. Can also be set via constructor.
415              
416             =head2 command_timeout([$ms])
417              
418             Get or set the command timeout in milliseconds. Returns the current value,
419             or undef if not set. Can also be set via constructor. When changed while
420             connected, takes effect immediately on the active connection.
421              
422             =head2 on_error([$cb->($errstr)])
423              
424             Set error callback. With a CODE reference argument, replaces the handler
425             and returns the new handler. With C or without arguments, clears
426             the handler and returns undef.
427              
428             B Calling without arguments clears the handler. There is no way to
429             read the current handler without clearing it. This applies to all handler
430             methods (C, C, C, C).
431              
432             =head2 on_connect([$cb->()])
433              
434             Set connect callback. With a CODE reference argument, replaces the handler
435             and returns the new handler. With C or without arguments, clears
436             the handler and returns undef.
437              
438             =head2 on_disconnect([$cb->()])
439              
440             Set disconnect callback, called on both normal and error disconnections.
441             With a CODE reference argument, replaces the handler and returns the new
442             handler. With C or without arguments, clears the handler and
443             returns undef.
444              
445             =head2 on_push([$cb->($reply)])
446              
447             Set RESP3 push callback for server-initiated messages (Redis 6.0+).
448             The callback receives the decoded push message as an array reference.
449             With a CODE reference argument, replaces the handler and returns the new
450             handler. With C or without arguments, clears the handler and
451             returns undef. When changed while connected, takes effect immediately.
452              
453             $redis->on_push(sub {
454             my ($msg) = @_;
455             # $msg is an array ref, e.g. ['invalidate', ['key1', 'key2']]
456             });
457              
458             =head2 reconnect($enable, $delay_ms, $max_attempts)
459              
460             Configure automatic reconnection.
461              
462             $redis->reconnect(1); # enable with defaults (1s delay, unlimited)
463             $redis->reconnect(1, 0); # enable with immediate reconnect
464             $redis->reconnect(1, 2000); # enable with 2 second delay
465             $redis->reconnect(1, 1000, 5); # enable with 1s delay, max 5 attempts
466             $redis->reconnect(0); # disable
467              
468             C<$delay_ms> defaults to 1000 (1 second). 0 means immediate reconnect.
469             C<$max_attempts> defaults to 0 (unlimited).
470              
471             When enabled, the client will automatically attempt to reconnect on connection
472             failure or unexpected disconnection. Intentional C calls will
473             not trigger reconnection.
474              
475             =head2 reconnect_enabled
476              
477             Returns true (1) if automatic reconnection is enabled, false (0) otherwise.
478              
479             =head2 pending_count
480              
481             Returns the number of commands sent to Redis awaiting responses.
482             Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
483             included in this count.
484             When called from inside a command callback, the count includes the
485             current command (it is decremented after the callback returns).
486              
487             =head2 waiting_count
488              
489             Returns the number of commands queued locally (not yet sent to Redis).
490             These are commands that exceeded the C limit.
491              
492             =head2 max_pending($limit)
493              
494             Get or set the maximum number of concurrent commands sent to Redis.
495             Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
496             subject to this limit.
497             0 means unlimited (default). When the limit is reached, additional commands
498             are queued locally and sent as responses arrive.
499              
500             =head2 waiting_timeout($ms)
501              
502             Get or set the maximum time in milliseconds a command can wait in the local queue.
503             Commands exceeding this timeout are cancelled with "waiting timeout" error.
504             0 means unlimited (default). Returns the current value as an integer (0 when unset).
505              
506             =head2 resume_waiting_on_reconnect($bool)
507              
508             Get or set whether waiting commands are preserved on disconnect and resumed
509             after reconnection. Default is false (waiting commands cancelled on disconnect).
510              
511             =head2 priority($priority)
512              
513             Get or set the priority for the underlying libev IO watchers. Higher priority
514             watchers are invoked before lower priority ones when multiple watchers are
515             pending. Valid range is -2 (lowest) to +2 (highest), with 0 being the default.
516             Values outside this range are clamped automatically.
517             Can be changed at any time, including while connected.
518              
519             $redis->priority(1); # higher priority
520             $redis->priority(-1); # lower priority
521             $redis->priority(99); # clamped to 2
522             my $prio = $redis->priority; # get current priority
523              
524             =head2 keepalive($seconds)
525              
526             Get or set the TCP keepalive interval in seconds. When set, the OS sends
527             periodic probes on idle connections to detect dead peers. 0 means disabled
528             (default). When set to a positive value while connected, takes effect
529             immediately. Setting to 0 while connected records the preference for future
530             connections but does not disable keepalives on the current socket.
531              
532             =head2 prefer_ipv4($bool)
533              
534             Get or set IPv4 preference for DNS resolution. Mutually exclusive with
535             C (setting one clears the other). Takes effect on the next
536             connection.
537              
538             =head2 prefer_ipv6($bool)
539              
540             Get or set IPv6 preference for DNS resolution. Mutually exclusive with
541             C (setting one clears the other). Takes effect on the next
542             connection.
543              
544             =head2 source_addr($addr)
545              
546             Get or set the local source address to bind to when connecting. This is
547             useful on multi-homed hosts to control which network interface is used.
548             Pass C to clear. Takes effect on the next TCP connection (has no
549             effect on Unix socket connections).
550              
551             =head2 tcp_user_timeout($ms)
552              
553             Get or set the TCP user timeout in milliseconds. This controls how long
554             transmitted data may remain unacknowledged before the connection is dropped.
555             0 means use the OS default. Takes effect on the next connection.
556              
557             =head2 cloexec($bool)
558              
559             Get or set the close-on-exec flag for the Redis socket. When enabled, the
560             socket is automatically closed in child processes after fork+exec. Enabled
561             by default. Takes effect on the next connection.
562              
563             =head2 reuseaddr($bool)
564              
565             Get or set SO_REUSEADDR on the Redis socket. Allows rebinding to an address
566             still in TIME_WAIT state. Disabled by default. Takes effect on the next
567             connection.
568              
569             =head2 skip_waiting
570              
571             Cancel only waiting (not yet sent) command callbacks. Each callback is invoked
572             with C<(undef, "skipped")>. In-flight commands continue normally.
573              
574             =head2 skip_pending
575              
576             Cancel all pending and waiting command callbacks. Each Perl callback is
577             invoked immediately with C<(undef, "skipped")>. For pending commands,
578             the internal hiredis tracking entry remains until a reply arrives (which
579             is then discarded); no second callback fires.
580              
581             =head2 can($method)
582              
583             Returns code reference if method is available, undef otherwise.
584             Methods installed via AUTOLOAD (Redis commands) will return true after first call.
585              
586             =head1 DESTRUCTION BEHAVIOR
587              
588             When an EV::Redis object is destroyed (goes out of scope or is explicitly
589             undefined) while commands are still pending or waiting, hiredis invokes all
590             pending command callbacks with a disconnect error, and EV::Redis invokes
591             all waiting queue callbacks with C<"disconnected">. This ensures callbacks
592             are not orphaned.
593              
594             For predictable cleanup, explicitly disconnect before destruction:
595              
596             $redis->disconnect; # Clean disconnect, callbacks get error
597             undef $redis; # Safe to destroy
598              
599             Or use skip methods to cancel with a specific error message:
600              
601             $redis->skip_pending; # Invokes callbacks with (undef, "skipped")
602             $redis->skip_waiting;
603             $redis->disconnect;
604             undef $redis;
605              
606             B If your callbacks close over the C<$redis> variable,
607             this creates a reference cycle (C<$redis> -> object -> callback -> C<$redis>)
608             that prevents garbage collection. Break the cycle before the object goes out
609             of scope by clearing callbacks:
610              
611             $redis->on_error(undef);
612             $redis->on_connect(undef);
613             $redis->on_disconnect(undef);
614             $redis->on_push(undef);
615              
616             =head1 BENCHMARKS
617              
618             Measured on Linux with Unix socket connection, 100-byte values, Perl 5.40,
619             Redis 8.x (C):
620              
621             Pipeline SET ~107K ops/sec
622             Pipeline GET ~112K ops/sec
623             Mixed workload ~112K ops/sec
624             Fire-and-forget SET ~655K ops/sec
625             Sequential round-trip ~39K ops/sec (SET+GET pairs)
626              
627             Fire-and-forget mode (no callback) is roughly 6x faster than callback mode
628             due to zero Perl-side overhead per command. Pipeline throughput is bounded
629             by the event loop round-trip, not by hiredis or the network.
630              
631             Flow control (C) has minimal impact at reasonable limits:
632              
633             unlimited ~180K ops/sec
634             max_pending=500 ~186K ops/sec
635             max_pending=100 ~146K ops/sec
636              
637             Run C for full results. Set C and
638             C environment variables to customize.
639              
640             =head1 AUTHOR
641              
642             Daisuke Murase (typester) (original L)
643              
644             vividsnow
645              
646             =head1 COPYRIGHT AND LICENSE
647              
648             Copyright (c) 2013 Daisuke Murase, 2026 vividsnow. All rights reserved.
649              
650             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
651              
652             =cut