[![Build Status](https://travis-ci.org/shogo82148/Redis-Fast.svg?branch=master)](https://travis-ci.org/shogo82148/Redis-Fast) [![MetaCPAN Release](https://badge.fury.io/pl/Redis-Fast.svg)](https://metacpan.org/release/Redis-Fast)
# NAME

Redis::Fast - Perl binding for Redis database

# SYNOPSIS

   ## Defaults to $ENV{REDIS_SERVER} or 127.0.0.1:6379
   my $redis = Redis::Fast->new;

   my $redis = Redis::Fast->new(server => 'redis.example.com:8080');

   ## Set the connection name (requires Redis 2.6.9)
   my $redis = Redis::Fast->new(
     server => 'redis.example.com:8080',
     name => 'my_connection_name',
   );
   my $generation = 0;
   my $redis = Redis::Fast->new(
     server => 'redis.example.com:8080',
     name => sub { "cache-$$-".++$generation },
   );

   ## Use UNIX domain socket
   my $redis = Redis::Fast->new(sock => '/path/to/socket');

   ## Enable auto-reconnect
   ## Try to reconnect every 500ms up to 60 seconds until success
   ## Die if you can't after that
   my $redis = Redis::Fast->new(reconnect => 60, every => 500_000);

   ## Try each 100ms up to 2 seconds (every is in microseconds)
   my $redis = Redis::Fast->new(reconnect => 2, every => 100_000);

   ## Disable the automatic utf8 encoding => much more performance
   ## !!!! This will be the default after 2.000, see ENCODING below
   my $redis = Redis::Fast->new(encoding => undef);

   ## Use all the regular Redis commands, they all accept a list of
   ## arguments
   ## See http://redis.io/commands for full list
   $redis->get('key');
   $redis->set('key' => 'value');
   $redis->sort('list', 'DESC');
   $redis->sort(qw{list LIMIT 0 5 ALPHA DESC});

   ## Add a coderef argument to run a command in the background
   $redis->sort(qw{list LIMIT 0 5 ALPHA DESC}, sub {
     my ($reply, $error) = @_;
     die "Oops, got an error: $error\n" if defined $error;
     print "$_\n" for @$reply;
   });
   long_computation();
   $redis->wait_all_responses;
   ## or
   $redis->wait_one_response();

   ## Or run a large batch of commands in a pipeline
   my %hash = _get_large_batch_of_commands();
   $redis->hset('h', $_, $hash{$_}, sub {}) for keys %hash;
   $redis->wait_all_responses;

   ## Publish/Subscribe
   $redis->subscribe(
     'topic_1',
     'topic_2',
     sub {
       my ($message, $topic, $subscribed_topic) = @_

         ## $subscribed_topic can be different from topic if
         ## you use psubscribe() with wildcards
     }
   );
   $redis->psubscribe('nasdaq.*', sub {...});

   ## Blocks and waits for messages, calls subscribe() callbacks
   ##  ... forever
   my $timeout = 10;
   $redis->wait_for_messages($timeout) while 1;

   ##  ... until some condition
   my $keep_going = 1; ## other code will set to false to quit
   $redis->wait_for_messages($timeout) while $keep_going;

   $redis->publish('topic_1', 'message');

# DESCRIPTION

`Redis::Fast` is a wrapper around Salvatore Sanfilippo's
[hiredis](https://github.com/redis/hiredis) C client.
It is compatible with [Redis.pm](https://github.com/melo/perl-redis).

This version supports protocol 2.x (multi-bulk) or later of Redis available at
[https://github.com/antirez/redis/](https://github.com/antirez/redis/).

## Reconnect on error

Besides auto-reconnect when the connection is closed, `Redis::Fast` supports
reconnecting on the specified errors by the `reconnect_on_error` option.
Here's an example that will reconnect when receiving `READONLY` error:

   my $r = Redis::Fast->new(
     reconnect          => 1, # The value greater than 0 is required
     reconnect_on_error => sub {
       my ($error, $ret, $command) = @_;
       if ($error =~ /READONLY You can't write against a read only slave/) {
         # force reconnect
         return 1;
       }
       # do nothing
       return -1;
     },
   );

This feature is useful when using Amazon ElastiCache.
Once failover happens, Amazon ElastiCache will switch the master
we currently connected with to a slave,
leading to the following writes fails with the error `READONLY`.
Using `reconnect_on_error`, we can force the connection to reconnect on this error
in order to connect to the new master.
If your Elasticache Redis is enabled to be set an option for [close-on-slave-write](https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/ParameterGroups.Redis.html#ParameterGroups.Redis.2-8-23),
this feature might be unnecessary.

The return value of `reconnect_on_error` should be greater than `-2`. `-1` means that
`Redis::Fast` behaves the same as without this option. `0` and greater than `0`
means that `Redis::Fast` forces to reconnect and then
wait for a next force reconnect until this value seconds elapse.
This unit is a second, and the type is double. For example, 0.01 means 10 milliseconds.

Note: This feature is not supported for the subscribed mode.

# PERFORMANCE IN SYNCHRONIZE MODE

## Redis.pm

   Benchmark: running 00_ping, 10_set, 11_set_r, 20_get, 21_get_r, 30_incr, 30_incr_r, 40_lpush, 50_lpop, 90_h_get, 90_h_set for at least 5 CPU seconds...
      00_ping:  8 wallclock secs ( 0.69 usr +  4.77 sys =  5.46 CPU) @ 5538.64/s (n=30241)
       10_set:  8 wallclock secs ( 1.07 usr +  4.01 sys =  5.08 CPU) @ 5794.09/s (n=29434)
     11_set_r:  7 wallclock secs ( 0.42 usr +  4.84 sys =  5.26 CPU) @ 5051.33/s (n=26570)
       20_get:  8 wallclock secs ( 0.69 usr +  4.82 sys =  5.51 CPU) @ 5080.40/s (n=27993)
     21_get_r:  7 wallclock secs ( 2.21 usr +  3.09 sys =  5.30 CPU) @ 5389.06/s (n=28562)
      30_incr:  7 wallclock secs ( 0.69 usr +  4.73 sys =  5.42 CPU) @ 5671.77/s (n=30741)
    30_incr_r:  7 wallclock secs ( 0.85 usr +  4.31 sys =  5.16 CPU) @ 5824.42/s (n=30054)
     40_lpush:  8 wallclock secs ( 0.60 usr +  4.77 sys =  5.37 CPU) @ 5832.59/s (n=31321)
      50_lpop:  7 wallclock secs ( 1.24 usr +  4.17 sys =  5.41 CPU) @ 5112.75/s (n=27660)
     90_h_get:  7 wallclock secs ( 0.63 usr +  4.65 sys =  5.28 CPU) @ 5716.29/s (n=30182)
     90_h_set:  7 wallclock secs ( 0.65 usr +  4.74 sys =  5.39 CPU) @ 5593.14/s (n=30147)

## Redis::Fast

Redis::Fast is 50% faster than Redis.pm.

   Benchmark: running 00_ping, 10_set, 11_set_r, 20_get, 21_get_r, 30_incr, 30_incr_r, 40_lpush, 50_lpop, 90_h_get, 90_h_set for at least 5 CPU seconds...
      00_ping:  9 wallclock secs ( 0.18 usr +  4.84 sys =  5.02 CPU) @ 7939.24/s (n=39855)
       10_set: 10 wallclock secs ( 0.31 usr +  5.40 sys =  5.71 CPU) @ 7454.64/s (n=42566)
     11_set_r:  9 wallclock secs ( 0.31 usr +  4.87 sys =  5.18 CPU) @ 7993.05/s (n=41404)
       20_get: 10 wallclock secs ( 0.27 usr +  4.84 sys =  5.11 CPU) @ 8350.68/s (n=42672)
     21_get_r: 10 wallclock secs ( 0.32 usr +  5.17 sys =  5.49 CPU) @ 8238.62/s (n=45230)
      30_incr:  9 wallclock secs ( 0.23 usr +  5.27 sys =  5.50 CPU) @ 8221.82/s (n=45220)
    30_incr_r:  8 wallclock secs ( 0.28 usr +  4.91 sys =  5.19 CPU) @ 8092.29/s (n=41999)
     40_lpush:  9 wallclock secs ( 0.18 usr +  5.06 sys =  5.24 CPU) @ 8312.02/s (n=43555)
      50_lpop:  9 wallclock secs ( 0.20 usr +  4.84 sys =  5.04 CPU) @ 8010.12/s (n=40371)
     90_h_get:  9 wallclock secs ( 0.19 usr +  5.51 sys =  5.70 CPU) @ 7467.72/s (n=42566)
     90_h_set:  8 wallclock secs ( 0.28 usr +  4.83 sys =  5.11 CPU) @ 7724.07/s (n=39470)o

# PERFORMANCE IN PIPELINE MODE

   #!/usr/bin/perl
   use warnings;
   use strict;
   use Time::HiRes qw/time/;
   use Redis;

   my $count = 100000;
   {
       my $r = Redis->new;
       my $start = time;
       for(1..$count) {
           $r->set('hoge', 'fuga', sub{});
       }
       $r->wait_all_responses;
       printf "Redis.pm:\n%.2f/s\n", $count / (time - $start);
   }

   {
       my $r = Redis::Fast->new;
       my $start = time;
       for(1..$count) {
           $r->set('hoge', 'fuga', sub{});
       }
       $r->wait_all_responses;
       printf "Redis::Fast:\n%.2f/s\n", $count / (time - $start);
   }

Redis::Fast is 4x faster than Redis.pm in pipeline mode.

   Redis.pm:
   22588.95/s
   Redis::Fast:
   81098.01/s

# AUTHOR

Ichinose Shogo <[email protected]>

# SEE ALSO

- [Redis.pm](https://github.com/melo/perl-redis)

# LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.