EV-Redis

 view release on metacpan or  search on metacpan

lib/EV/Redis.pm  view on Meta::CPAN

package EV::Redis;
use strict;
use warnings;

use Carp ();
use EV;

BEGIN {
    use XSLoader;
    our $VERSION = '0.09';
    XSLoader::load __PACKAGE__, $VERSION;
}

sub new {
    my ($class, %args) = @_;

    Carp::croak("Cannot specify both 'host' and 'path'")
        if exists $args{host} && exists $args{path};
    Carp::croak("Cannot specify both 'prefer_ipv4' and 'prefer_ipv6'")
        if $args{prefer_ipv4} && $args{prefer_ipv6};

    my $loop = $args{loop} // EV::default_loop;
    my $self = $class->_new($loop);

    $self->on_error($args{on_error} // sub { die @_ });
    $self->on_connect($args{on_connect}) if exists $args{on_connect};
    $self->on_disconnect($args{on_disconnect}) if exists $args{on_disconnect};
    $self->on_push($args{on_push}) if exists $args{on_push};
    $self->connect_timeout($args{connect_timeout}) if defined $args{connect_timeout};
    $self->command_timeout($args{command_timeout}) if defined $args{command_timeout};
    $self->max_pending($args{max_pending}) if defined $args{max_pending};
    $self->waiting_timeout($args{waiting_timeout}) if defined $args{waiting_timeout};
    $self->resume_waiting_on_reconnect($args{resume_waiting_on_reconnect}) if defined $args{resume_waiting_on_reconnect};
    $self->priority($args{priority}) if defined $args{priority};
    $self->keepalive($args{keepalive}) if defined $args{keepalive};
    $self->prefer_ipv4($args{prefer_ipv4}) if exists $args{prefer_ipv4};
    $self->prefer_ipv6($args{prefer_ipv6}) if exists $args{prefer_ipv6};
    $self->source_addr($args{source_addr}) if defined $args{source_addr};
    $self->tcp_user_timeout($args{tcp_user_timeout}) if defined $args{tcp_user_timeout};
    $self->cloexec($args{cloexec}) if exists $args{cloexec};
    $self->reuseaddr($args{reuseaddr}) if exists $args{reuseaddr};

    # Configure reconnect if specified
    if ($args{reconnect}) {
        $self->reconnect(
            1,
            $args{reconnect_delay} // 1000,
            $args{max_reconnect_attempts} // 0
        );
    }

    # Configure TLS if specified (must be done before connect)
    if ($args{tls}) {
        Carp::croak("TLS support not compiled in; rebuild with EV_REDIS_SSL=1")
            unless $self->has_ssl;
        Carp::croak("TLS requires 'host' parameter (not 'path')")
            if exists $args{path};
        $self->_setup_ssl_context(
            $args{tls_ca}, $args{tls_capath}, $args{tls_cert}, $args{tls_key},
            $args{tls_server_name},
            exists $args{tls_verify} ? ($args{tls_verify} ? 1 : 0) : 1,
        );
    }

    if (exists $args{host}) {
        Carp::croak("'host' must be a defined string") unless defined $args{host};
        defined $args{port}
            ? $self->connect($args{host}, $args{port})
            : $self->connect($args{host});
    }
    elsif (exists $args{path}) {
        Carp::croak("'path' must be a defined string") unless defined $args{path};
        $self->connect_unix($args{path});
    }

    $self;
}

our $AUTOLOAD;

sub AUTOLOAD {
    (my $method = $AUTOLOAD) =~ s/.*:://;
    return if $method eq 'DESTROY';

    my $sub = sub {
        my $self = shift;
        $self->command($method, @_);
    };

    no strict 'refs';
    *$method = $sub;
    goto $sub;
}

sub can {

lib/EV/Redis.pm  view on Meta::CPAN


=item * on_disconnect => $cb->()

Disconnect callback will be called when disconnection occurs (both normal and error cases).

This callback can be set by C<< $obj->on_disconnect($cb) >> method any time.

=item * on_push => $cb->($reply)

RESP3 push callback for server-initiated out-of-band messages (Redis 6.0+).
Called with the decoded push message (an array reference). This enables
client-side caching invalidation and other server-push features.

This callback can be set by C<< $obj->on_push($cb) >> method any time.

=item * connect_timeout => $num_of_milliseconds

Connection timeout.

=item * command_timeout => $num_of_milliseconds

Command timeout.

=item * max_pending => $num

Maximum number of commands sent to Redis concurrently. When this limit is reached,
additional commands are queued locally and sent as responses arrive.
0 means unlimited (default). Use C<waiting_count> to check the local queue size.

=item * waiting_timeout => $num_of_milliseconds

Maximum time a command can wait in the local queue before being cancelled with
"waiting timeout" error. 0 means unlimited (default).

=item * resume_waiting_on_reconnect => $bool

Controls behavior of waiting queue on disconnect. If false (default), waiting
commands are cancelled with error on disconnect. If true, waiting commands are
preserved and resumed after successful reconnection.

=item * reconnect => $bool

Enable automatic reconnection on connection failure or unexpected disconnection.
Default is disabled (0).

=item * reconnect_delay => $num_of_milliseconds

Delay between reconnection attempts. Default is 1000 (1 second).

=item * max_reconnect_attempts => $num

Maximum number of reconnection attempts. 0 means unlimited. Default is 0.
Negative values are treated as 0 (unlimited).

=item * priority => $num

Priority for the underlying libev IO watchers. Higher priority watchers are
invoked before lower priority ones. Valid range is -2 (lowest) to +2 (highest),
with 0 being the default. See L<EV> documentation for details on priorities.

=item * keepalive => $seconds

Enable TCP keepalive with the specified interval in seconds. When enabled,
the OS will periodically send probes on idle connections to detect dead peers.
0 means disabled (default). Recommended for long-lived connections behind
NAT gateways or firewalls.

=item * prefer_ipv4 => $bool

Prefer IPv4 addresses when resolving hostnames. Mutually exclusive with
C<prefer_ipv6>.

=item * prefer_ipv6 => $bool

Prefer IPv6 addresses when resolving hostnames. Mutually exclusive with
C<prefer_ipv4>.

=item * source_addr => 'Str'

Local address to bind the outbound connection to. Useful on multi-homed
servers to select a specific network interface.

=item * tcp_user_timeout => $num_of_milliseconds

Set the TCP_USER_TIMEOUT socket option (Linux-specific). Controls how long
transmitted data may remain unacknowledged before the connection is dropped.
Helps detect dead connections faster on lossy networks.

=item * cloexec => $bool

Set SOCK_CLOEXEC on the Redis connection socket. Prevents the file descriptor
from leaking to child processes after fork/exec. Default is enabled.

=item * reuseaddr => $bool

Set SO_REUSEADDR on the Redis connection socket. Allows rebinding to an
address that is still in TIME_WAIT state. Default is disabled.

=item * tls => $bool

Enable TLS/SSL encryption for the connection. Requires that the module was
built with TLS support (auto-detected at build time, or forced with
C<EV_REDIS_SSL=1>). Only valid with C<host> connections, not C<path>.

=item * tls_ca => 'Str'

Path to CA certificate file for server verification. If not specified,
uses the system default CA store.

=item * tls_capath => 'Str'

Path to a directory containing CA certificate files in OpenSSL-compatible
format (hashed filenames). Alternative to C<tls_ca> for multiple CA certs.

=item * tls_cert => 'Str'

Path to client certificate file for mutual TLS authentication. Must be
specified together with C<tls_key>.

=item * tls_key => 'Str'

Path to client private key file. Must be specified together with C<tls_cert>.

lib/EV/Redis.pm  view on Meta::CPAN

    $redis->reconnect(1, 2000);              # enable with 2 second delay
    $redis->reconnect(1, 1000, 5);           # enable with 1s delay, max 5 attempts
    $redis->reconnect(0);                    # disable

C<$delay_ms> defaults to 1000 (1 second). 0 means immediate reconnect.
C<$max_attempts> defaults to 0 (unlimited).

When enabled, the client will automatically attempt to reconnect on connection
failure or unexpected disconnection. Intentional C<disconnect()> calls will
not trigger reconnection.

=head2 reconnect_enabled

Returns true (1) if automatic reconnection is enabled, false (0) otherwise.

=head2 pending_count

Returns the number of commands sent to Redis awaiting responses.
Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
included in this count.
When called from inside a command callback, the count includes the
current command (it is decremented after the callback returns).

=head2 waiting_count

Returns the number of commands queued locally (not yet sent to Redis).
These are commands that exceeded the C<max_pending> limit.

=head2 max_pending($limit)

Get or set the maximum number of concurrent commands sent to Redis.
Persistent commands (subscribe, psubscribe, ssubscribe, monitor) are not
subject to this limit.
0 means unlimited (default). When the limit is reached, additional commands
are queued locally and sent as responses arrive.

=head2 waiting_timeout($ms)

Get or set the maximum time in milliseconds a command can wait in the local queue.
Commands exceeding this timeout are cancelled with "waiting timeout" error.
0 means unlimited (default). Returns the current value as an integer (0 when unset).

=head2 resume_waiting_on_reconnect($bool)

Get or set whether waiting commands are preserved on disconnect and resumed
after reconnection. Default is false (waiting commands cancelled on disconnect).

=head2 priority($priority)

Get or set the priority for the underlying libev IO watchers. Higher priority
watchers are invoked before lower priority ones when multiple watchers are
pending. Valid range is -2 (lowest) to +2 (highest), with 0 being the default.
Values outside this range are clamped automatically.
Can be changed at any time, including while connected.

    $redis->priority(1);     # higher priority
    $redis->priority(-1);    # lower priority
    $redis->priority(99);    # clamped to 2
    my $prio = $redis->priority;  # get current priority

=head2 keepalive($seconds)

Get or set the TCP keepalive interval in seconds. When set, the OS sends
periodic probes on idle connections to detect dead peers. 0 means disabled
(default). When set to a positive value while connected, takes effect
immediately. Setting to 0 while connected records the preference for future
connections but does not disable keepalives on the current socket.

=head2 prefer_ipv4($bool)

Get or set IPv4 preference for DNS resolution. Mutually exclusive with
C<prefer_ipv6> (setting one clears the other). Takes effect on the next
connection.

=head2 prefer_ipv6($bool)

Get or set IPv6 preference for DNS resolution. Mutually exclusive with
C<prefer_ipv4> (setting one clears the other). Takes effect on the next
connection.

=head2 source_addr($addr)

Get or set the local source address to bind to when connecting. This is
useful on multi-homed hosts to control which network interface is used.
Pass C<undef> to clear. Takes effect on the next TCP connection (has no
effect on Unix socket connections).

=head2 tcp_user_timeout($ms)

Get or set the TCP user timeout in milliseconds. This controls how long
transmitted data may remain unacknowledged before the connection is dropped.
0 means use the OS default. Takes effect on the next connection.

=head2 cloexec($bool)

Get or set the close-on-exec flag for the Redis socket. When enabled, the
socket is automatically closed in child processes after fork+exec. Enabled
by default. Takes effect on the next connection.

=head2 reuseaddr($bool)

Get or set SO_REUSEADDR on the Redis socket. Allows rebinding to an address
still in TIME_WAIT state. Disabled by default. Takes effect on the next
connection.

=head2 skip_waiting

Cancel only waiting (not yet sent) command callbacks. Each callback is invoked
with C<(undef, "skipped")>. In-flight commands continue normally.

=head2 skip_pending

Cancel all pending and waiting command callbacks. Each Perl callback is
invoked immediately with C<(undef, "skipped")>. For pending commands,
the internal hiredis tracking entry remains until a reply arrives (which
is then discarded); no second callback fires.

=head2 can($method)

Returns code reference if method is available, undef otherwise.
Methods installed via AUTOLOAD (Redis commands) will return true after first call.

=head1 DESTRUCTION BEHAVIOR

When an EV::Redis object is destroyed (goes out of scope or is explicitly
undefined) while commands are still pending or waiting, hiredis invokes all
pending command callbacks with a disconnect error, and EV::Redis invokes



( run in 2.575 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )