Net::Async::Redis - talk to Redis servers via IO::Async
use Net::Async::Redis; use Future::AsyncAwait; use IO::Async::Loop; my $loop = IO::Async::Loop->new; $loop->add(my $redis = Net::Async::Redis->new); (async sub { await $redis->connect; my $value = await $redis->get('some_key'); $value ||= await $redis->set(some_key => 'some_value'); print "Value: $value"; })->()->get; # You can also use ->then chaining, see L<Future> for more details $redis->connect->then(sub { $redis->get('some_key') })->then(sub { my $value = shift; return Future->done($value) if $value; $redis->set(some_key => 'some_value') })->on_done(sub { print "Value: " . shift; })->get; # ... or with Future::AsyncAwait (recommended) await $redis->connect; my $value = await $redis->get('some_key'); $value ||= await $redis->set(some_key => 'some_value'); print "Value: $value";
Provides client access for dealing with Redis servers.
6ee Net::Async::Redis::Commands for the full list of commands, this list is autogenerated from the official documentation here:
https://redis.io/commands
This is intended to be a near-complete low-level client module for asynchronous Redis support. See Net::Async::Redis::Server for a (limited) Perl server implementation.
This is an unofficial Perl port, and not endorsed by the Redis server maintainers in any way.
Current features include:
all commands as of 6.2 (January 2021), see https://redis.io/commands for the methods and parameters
pub/sub support, see "METHODS - Subscriptions"
pipelining, see "pipeline_depth"
transactions, see "METHODS - Transactions"
streams and consumer groups, via "XADD" in Net::Async::Redis::Commands and related methods
client-side caching, see "METHODS - Clientside caching"
"https://github.com/antirez/RESP3/blob/master/spec.md" in RESP3 protocol for Redis 6 and above, allowing pubsub on the same connection as regular commands
As with any other IO::Async::Notifier-based module, you'll need to add this to an IO::Async::Loop:
my $loop = IO::Async::Loop->new; $loop->add( my $redis = Net::Async::Redis->new );
then connect to the server:
$redis->connect ->then(sub { # You could achieve a similar result by passing client_name in # constructor or ->connect parameters $redis->client_setname("example client") })->get;
One of the most common Redis scenarios is as a key/value store. The "get" and "set" methods are typically used here:
$redis->set(some_key => 'some value') ->then(sub { $redis->get('some_key') })->on_done(sub { my ($value) = @_; print "Read back value [$value]\n"; })->retain;
See the next section for more information on what these methods are actually returning.
Requests are implemented as methods on the Net::Async::Redis object. These typically return a Future which will resolve once ready:
my $future = $redis->incr("xyz") ->on_done(sub { print "result of increment was " . shift . "\n" });
For synchronous code, call ->get on that Future:
->get
print "Database has " . $redis->dbsize->get . " total keys\n";
This means you can end up with ->get being called on the result of ->get, note that these are two very different methods:
$redis ->get('some key') # this is being called on $redis, and is issuing a GET request ->get # this is called on the returned Future, and blocks until the value is ready
Typical async code would not be expected to use the "get" in Future method extensively; often only calling it in one place at the top level in the code.
In RESP3 some of the responses are structured differently from RESP2. Net::Async::Redis guarantees the same structure unless you have explicitly requested the new types using the "configure" hashrefs option, which is disabled by default.
hashrefs
Generally RESP3 is recommended if you have Redis version 6 or later installed: it allows subscription operations to share the same connection as regular Redis traffic.
Since Future is used for deferred results, failure is indicated by a failing Future with failure category of redis.
redis
The "catch" in Future feature may be useful for handling these:
$redis->lpush(key => $value) ->catch( redis => sub { warn "probably an incorrect type, cannot push value"; Future->done } )->get;
Note that this module uses Future::AsyncAwait internally.
Defaults to false, this can be controlled by the USE_OPENTRACING environment variable. This provides a way to set the default opentracing mode for all Net::Async::Redis instances - you can enable/disable for a specific instance via "configure":
USE_OPENTRACING
$redis->configure(opentracing => 1);
When enabled, this will create a span for every Redis request. See OpenTracing::Any for details.
NOTE: For a full list of the Redis methods supported by this module, please see Net::Async::Redis::Commands.
Applies configuration parameters - currently supports:
host
port
auth
database
pipeline_depth
stream_read_len
stream_write_len
on_disconnect
client_name
opentracing
protocol - either 'resp2' or 'resp3', default is autodetect
protocol
hashrefs - RESP3 (Redis 6.0+) supports more data types, currently the only difference this makes to us is that it now supports hashrefs for key/value pairs. This is disabled by default to ensure compatibility across newer+older versions.
Note that enabling hashrefs will cause connections to fail if the server does not support RESP3.
Returns the host or IP address for the Redis server.
Returns the port used for connecting to the Redis server.
Returns the database index used when connecting to the Redis server.
See the "select" in Net::Async::Redis::Commands method for details.
Returns the Redis endpoint URI instance.
Returns the buffer size when reading from a Redis connection.
Defaults to 1MB, reduce this if you're dealing with a lot of connections and want to minimise memory usage. Alternatively, if you're reading large amounts of data and spend too much time in needless epoll_wait calls, try a larger value.
epoll_wait
Returns the buffer size when writing to Redis connections, in bytes. Defaults to 1MB.
See "stream_read_len".
Returns the name used for this client when connecting.
Connects to the Redis server.
Will use the "configure"d parameters if available, but as a convenience can be passed additional parameters which will then be applied as if you had called "configure" with those beforehand. This also means that they will be preserved for subsequent "connect" calls.
Establishes a connection if needed, otherwise returns an immediately-available Future instance.
The string describing the remote endpoint.
A string describing the local endpoint, usually host:port.
host:port
See https://redis.io/topics/pubsub for more details on this topic. There's also more details on the internal implementation in Redis here: https://making.pusher.com/redis-pubsub-under-the-hood/.
NOTE: On Redis versions prior to 6.0, you will need a separate connection for subscriptions; you cannot share a connection for regular requests once any of the "subscribe" or "psubscribe" methods have been called on an existing connection.
With Redis 6.0, a newer protocol version (RESP3) is used by default, and this is quite happy to support pubsub activity on the same connection as other traffic.
Subscribes to a pattern.
Example:
# Subscribe to 'info::*' channels, i.e. any message # that starts with the C<info::> prefix, and prints them # with a timestamp. $redis_connection->psubscribe('info::*') ->then(sub { my $sub = shift; $sub->map('payload') ->each(sub { print localtime . ' ' . $_ . "\n"; })->retain })->get; # this will block until the subscribe is confirmed. Note that you can't publish on # a connection that's handling subscriptions due to Redis protocol restrictions. $other_redis_connection->publish('info::example', 'a message here')->get;
Returns a Future which resolves to a Net::Async::Redis::Subscription instance.
Subscribes to one or more channels.
# Subscribe to 'notifications' channel, # print the first 5 messages, then unsubscribe $redis->subscribe('notifications') ->then(sub { my $sub = shift; $sub->events ->map('payload') ->take(5) ->say ->completed })->then(sub { $redis->unsubscribe('notifications') })->get
Executes the given code in a Redis MULTI transaction.
MULTI
This will cause each of the requests to be queued on the server, then applied in a single atomic transaction.
Note that the commands will resolve only after the transaction is committed: for example, when the "set" command is issued, Redis will return QUEUED. This information is not used as the result - we only pass through the immediate response if there was an error. The Future representing the response will be marked as done once the EXEC command is applied and we have the results back.
QUEUED
EXEC
$redis->multi(sub { my $tx = shift; $tx->incr('some::key')->on_done(sub { print "Final value for incremented key was " . shift . "\n"; }); $tx->set('other::key => 'test data') })->then(sub { my ($success, $failure) = @_; return Future->fail("Had $failure failures, expecting everything to succeed") if $failure; print "$success succeeded\m"; return Future->done; })->retain;
Enable clientside caching by passing a true value for client_side_caching_enabled in "configure" or "new". This is currently experimental, and only operates on "get" in Net::Async::Redis::Commands requests.
client_side_caching_enabled
See https://redis.io/topics/client-side-caching for more details on this feature.
Returns a Future representing the client-side cache connection status, if there is one.
Returns the Cache::LRU instance used for the client-side cache.
Returns true if the client-side cache is enabled.
Returns the current client-side cache size, as a number of entries.
A convenience wrapper around the keyspace notifications API.
Provides the necessary setup to establish a PSUBSCRIBE subscription on the __keyspace@*__ namespace, setting the configuration required for this to start emitting events, and then calls $code with each event.
PSUBSCRIBE
__keyspace@*__
$code
Note that this will switch the connection into pubsub mode on versions of Redis older than 6.0, so it will no longer be available for any other activity. This limitation does not apply on Redis 6 or above.
Use * to listen for all keyspace changes.
*
Resolves to a Ryu::Source instance.
Number of requests awaiting responses before we start queuing. This defaults to an arbitrary value of 100 requests.
Note that this does not apply when in transaction (MULTI) mode.
See https://redis.io/topics/pipelining for more details on this concept.
Indicates whether OpenTracing::Any support is enabled.
This are still supported, but no longer recommended.
Called for each incoming message.
Passes off the work to "handle_pubsub_message" or the next queue item, depending on whether we're dealing with subscriptions at the moment.
Attempt to process next pending request when in pipeline mode.
Called when there's an error response.
Deal with an incoming pubsub-related message.
Represents the IO::Async::Stream instance for the active Redis connection.
Called when the socket is closed.
Generate a label for the given command list.
Queues or executes the given command.
A Ryu::Async instance for source/sink creation.
Factory method for creating new Future instances.
Returns the Net::Async::Redis::Protocol instance used for encoding and decoding messages.
Some other Redis implementations on CPAN:
Mojo::Redis2 - nonblocking, using the Mojolicious framework, actively maintained
MojoX::Redis - changelog mentions that this was obsoleted by Mojo::Redis, although there have been new versions released since then
RedisDB - another synchronous (blocking) implementation, handles pub/sub and autoreconnect
Cache::Redis - wrapper around RedisDB
Redis::Fast - wraps hiredis, faster than Redis
hiredis
Redis::Jet - also XS-based, docs mention very early development stage but appears to support pipelining and can handle newer commands via ->command.
very early development stage
->command
Redis - synchronous (blocking) implementation, handles pub/sub and autoreconnect
HiRedis::Raw - another hiredis wrapper
Tom Molesworth <TEAM@cpan.org>
acl_cat, acl_deluser, acl_genpass, acl_getuser, acl_help, acl_list, acl_load, acl_log, acl_save, acl_setuser, acl_users, acl_whoami, append, auth, bgrewriteaof, bgsave, bitcount, bitfield, bitop, bitpos, blmove, blpop, brpop, brpoplpush, bzpopmax, bzpopmin, client_caching, client_getname, client_getredir, client_id, client_info, client_kill, client_list, client_pause, client_reply, client_setname, client_tracking, client_trackinginfo, client_unblock, client_unpause, cluster_addslots, cluster_bumpepoch, cluster_count_failure_reports, cluster_countkeysinslot, cluster_delslots, cluster_failover, cluster_flushslots, cluster_forget, cluster_getkeysinslot, cluster_info, cluster_keyslot, cluster_meet, cluster_myid, cluster_nodes, cluster_replicas, cluster_replicate, cluster_reset, cluster_saveconfig, cluster_set_config_epoch, cluster_setslot, cluster_slaves, cluster_slots, command, command_count, command_getkeys, command_info, config_get, config_resetstat, config_rewrite, config_set, copy, dbsize, debug_object, debug_segfault, decr, decrby, del, dump, echo, eval, evalsha, exists, expire, expireat, flushall, flushdb, geoadd, geodist, geohash, geopos, georadius, georadiusbymember, geosearch, geosearchstore, getbit, getrange, getset, hdel, hello, hexists, hget, hgetall, hincrby, hincrbyfloat, hkeys, hlen, hmget, hmset, hscan, hset, hsetnx, hstrlen, hvals, incr, incrby, incrbyfloat, info, lastsave, latency_doctor, latency_graph, latency_help, latency_history, latency_latest, latency_reset, lindex, linsert, llen, lmove, lolwut, lpop, lpos, lpush, lpushx, lrange, lrem, lset, ltrim, memory_doctor, memory_help, memory_malloc_stats, memory_purge, memory_stats, memory_usage, mget, migrate, module_list, module_load, module_unload, monitor, move, mset, msetnx, object, persist, pexpire, pexpireat, pfadd, pfcount, pfmerge, ping, psetex, psync, pttl, publish, pubsub, punsubscribe, quit, randomkey, readonly, readwrite, rename, renamenx, replicaof, reset, restore, role, rpop, rpoplpush, rpush, rpushx, sadd, save, scan, scard, script_debug, script_exists, script_flush, script_kill, script_load, sdiff, sdiffstore, select, set, setbit, setex, setnx, setrange, shutdown, sinter, sinterstore, sismember, slaveof, slowlog, smembers, smismember, smove, sort, spop, srandmember, srem, sscan, stralgo, strlen, sunion, sunionstore, swapdb, sync, time, touch, ttl, type, unlink, unsubscribe, unwatch, wait, watch, xack, xadd, xautoclaim, xclaim, xdel, xgroup, xinfo, xlen, xpending, xrange, xrevrange, xtrim, zadd, zcard, zcount, zdiff, zdiffstore, zincrby, zinter, zinterstore, zlexcount, zmscore, zpopmax, zpopmin, zrangebylex, zrangestore, zrank, zrem, zremrangebylex, zremrangebyrank, zremrangebyscore, zrevrangebylex, zrevrank, zscan, zscore, zunion, zunionstore
add_child, adopt_future, adopted_futures, can_event, children, configure_unknown, debug_printf, get_loop, invoke_error, invoke_event, loop, make_event_cb, maybe_invoke_event, maybe_make_event_cb, new, notifier_name, parent, remove_child, remove_from_parent
With thanks to the following for contributing patches, bug reports, tests and feedback:
BINARY@cpan.org
PEVANS@cpan.org
@eyadof
Nael Alolwani
Copyright Tom Molesworth and others 2015-2020. Licensed under the same terms as Perl itself.
To install Net::Async::Redis, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Net::Async::Redis
CPAN shell
perl -MCPAN -e shell install Net::Async::Redis
For more information on module installation, please visit the detailed CPAN module installation guide.