spade

♠ Spade, a robust, full-featured, multi-module, Redis client, with offline queue for commands, automatic socket reconnection and command rollback mechanisms for subscriptions, moreover, it supports caching for LUA scripts.

Usage no npm install needed!

<script type="module">
  import spade from 'https://cdn.skypack.dev/spade';
</script>

README

♠ Spade

NPM VERSION CODACY BADGE CODECLIMATE-TEST-COVERAGE LICENSE

NODE VERSION TRAVIS CI BUILD BUILD STATUS DEVDEPENDENCY STATUS

NPM MONTHLY NPM YEARLY NPM TOTAL

NPM GRAPH

Spade, a robust, full-featured, multi-module, Redis client:

  • It offers the ability to restrict commands to a particular Redis version via the semver constructor option. Specifying this option turns Spade in develop mode, it enables a series of mix-ins to get brief descriptions of every implemented command.
  • It implements a simple delayed mechanism for re-connecting to socket when the client connection was not voluntarily interrupted.
  • It collects commands in the queue also when the client is offline.
  • It implements an automatic command rollback mechanism for subscriptions when connection is lost and becames ready again.
  • It implements AUTH logic and automatic db SELECT on socket (re)connection, configurable via the security constructor option.
  • It offers automatic LUA scripts caching, using a simple NFU with linear aging eviction algorithm ( NFU stands for Not Frequently Used ).
  • It correctly handles multiple (p)(un)subscription commands as we will expect (1 command : multiple replies : multiple callback execution); it was well tested against some weird edge cases. See tests for pubsub.
  • It supports the new PING command signature also in PubSub mode.
  • It implements a polling mechanism, useful to force automatic re-connection when client hangs while in PubSub mode.
  • It facilitates scanning of Redis keyspace, implementing some simple iterators for SCAN/HSCAN/SSCAN/ZSCAN commands. See #loadIterators.

Spade makes use of some well tested modules:

  • Σ Syllabus module for command encoding and command helpers mix-ins, it also offers a series of helpers functions to convert a raw data reply in a usable format.

Internally it uses Hoar module to handle Semantic Versioning 2.0, Sermone to encode commands, Abaco and Bolgia modules to get some utilities. Moreover, Syllabus mantains a cache for LUA scripts, using the Camphora module.

  • ♎ Libra module to handle bindings between commands which have been sent and relative Redis replies; it handles also commands queue rollbacks with the help of Train module.
  • Cocker module to properly handle socket reconnection when the connection is lost.
  • Hiboris, a utility module to load hiredis native parser, or to fall back to Boris, a pure js parser module for Redis string protocol; internally Boris uses Peela as command stack.
  • Cucu, a tiny module to handle the scheduled execution of repetitive methods/tasks.
  • Gerry, a tiny module to handle event logging to console, for debugging and testing purpose.
  • Dado, for running tests.
  • Vapid, a vacuous Redis implementation, with fully functional PubSub system.

NOTE : If you need a minimal Redis client based on ♠ Spade code, specific for PubSub and Monitor mode try 🂢 Deuces.

Table of Contents


Install

NOTE: only node engines ">=v0.10.x" are supported.

 $ npm install spade [-g]
 // clone repo
 $ git clone git@github.com:rootslab/spade.git

install and update devDependencies:

 $ cd spade/
 $ npm install
 # update
 $ npm update

require

var Spade = require( 'spade' );

See examples.

Run Tests

to run all test files, install devDependecies:

 $ cd spade/
 # install or update devDependecies 
 $ npm install 
 # run tests
 $ npm test

to execute a single test file simply do:

 $ node test/file-name.js

NOTE:

  • tests need a running Redis server instance, with default/stock configuration ( port 6379 ).
  • for some connection tests you need the Vapid devDependency, a vacuous Redis server module ( port 6380 ).

Run Benchmarks

run benchmarks for spade (fast/tight checks/turtle developer).

 $ cd spade/
 $ npm run bench

run benchmarks for node_redis (faster/loose checks/an army of contributors).

 $ cd spade/
 $ npm install redis
 $ npm run node_redis_bench

run benchmarks for ioredis (slowest/loose checks/unsafe pubsub).

 $ cd spade/
 $ npm install ioredis
 $ npm run ioredis_bench

NOTE:

  • benchmarks need a running Redis server instance, with default/stock configuration.
  • to switch to the faster hiredis native parser, install devDependencies .

Constructor

Create an instance, the argument within [ ] is optional.

Spade( [ Object opt ] )
// or
new Spade( [ Object opt ] )

Options

Default options are listed.

opt = {
    /*
     * Syllabus option to enable develop mode and restrict
     * commands to a particular Redis semantic version.
     * Use:
     * - boolean 'true' or string '*' for all commands available.
     * - semver string to restrict commands ( like '1.0.0' ).
     *
     * NOTE, develop mode enables some utility methods to get command
     * descriptions, like:
     * - Spade.mixins#info( String command ) get cmd infos
     * - Spade.mixins#size() get the current number of commands
     * - Spade.mixins#stick( [ Boolean attach ] ) attach #info to every mix-in.
     *
     * See https://github.com/rootslab/syllabus#properties-methods.
     */
    semver : null

    /*
     * Hiboris option. For default, the loading
     * of 'hiredis' native parser is disabled
     * in favour of ( the slower ) Boris JS parser.
     */
    , hiredis : false

    /*
     * Cocker socket options
     */
    , socket : {
        path : null
        , address : {
            // 'localhost'
            host : '127.0.0.1'
            , port : 6379
            , family : null
        }
        , reconnection : {
            trials : 3
            , interval : 1000
            /*
             * A value to use for calculating the pause between two
             * connection attempts. Default value is the golden ratio.
             * Final value is calculated as:
             * interval * Math.pow( factor, curr.attempts + 1 )
             */
            , factor : ( Math.sqrt( 5 ) + 1 ) / 2
        }
        , connection : {
            /*
             * encoding could be: 'ascii', 'utf8', 'utf16le' or 
             * 'ucs2','buffer'. It defaults to null or 'buffer'.
             */
            encoding : null
            /*
             * keepAlive defaults to true ( it is false in net.Socket ).
             * Specify a number to set also the initialDelay.
             */
            , keepAlive : true
            /*
             * 'timeout' event delay, default is 0 ( no timeout ).
             */
            , timeout : 0
            /*
            * noDelay is true for default, it disables the Nagle
            * algorithm ( no TCP data buffering for socket.write ).
            */
            , noDelay : true
            /*
             * If true, the socket won't automatically send a FIN
             * packet when the other end of the socket sends a FIN
             * packet. Defaults to false.
             */
            , allowHalfOpen : false
        }
    }
    /*
     * Security options.
     *
     * Options for db selection and password sending when the 
     * client connects to a particular host.
     * An entry will be automatically added with the socket.address
     * or socket.path defined in the constructor option. However,
     * two sample entries are already present in the cache, holding
     * default values from redis.conf. 
     *
     * Every entry should be a file path ('/path/to/file.sock'),
     * or a network path ('ip:port'), and should contain a:
     *
     * - 'requirepass' property, it contains the Redis password string
     * for the current host. It defaults to null.
     * Whenever a client connection is established and if an entry is
     * found in the security hash. an AUTH command will be sent to Redis,
     * before any other command in the command queue.
     *
     * - 'db' property, it defaults to 0. On every reconnection the first
     * command to send after AUTH is SELECT db. If db === -1, on client
     * reconnection the SELECT command will not been sent.
     *
     * NOTE: If the AUTH reply is erroneous, an 'authfailed' event will
     * be emitted, then the client will be automatically disconnected to
     * force re-AUTH on reconnection; it also happens if AUTH isn't required
     * by Redis, but was sent by the client.
     * If authorization is granted by Redis, an 'authorize' event will be
     * emitted, then if the command queue is not empty, it will be processed.
     */
     , security : {
        // a network path (ip:port)
        '127.0.0.1:6379' : {
            requirepass : null
            , db : 0
        }
        // a unix domain socket path
        , '/tmp/redis.sock' : {
            requirepass : null
            , db : 0
        }
    }
    /*
     * Command queue options.
     */
    , queue : {
        /*
         * Set the max size for the rollback queue.
         * It defaults to 2^16, to disable set it to 0.
         */
        rollback : 64 * 1024
        /*
         * Log the last access time to the queue's head.
         * It is disabled for default.
         *
         * NOTE: It is used to store the last time a reply was received. 
         */
        , timestamps : false
    }
}

Back to ToC


Properties

Don't mess with these properties!

/*
 * A property that holds the initial config object.
 */
Spade.options : Object

/*
 * An Object that holds all Redis commands/methods mix-ins
 * from Syllabus. It is a shortcut for Spade.mixins.commands.
 * See https://github.com/rootslab/syllabus#syllabus-commands.
 */
Spade.commands : Object

/*
 * A flag to indicate if the connection to Redis Server
 * is currently active.
 */
Spade.ready : Boolean

/*
 * A flag to avoid initializing scripts cache multiple times,
 * when the client is offline ( multiple #initCache() calls ).
 */
Spade.cacheready : Boolean

/*
 * An Object that holds all scheduled tasks.
 * See Spade#initTasks method to load defaults entries like 'polling'.
 * See Spade.qq property to handle tasks.
 */
Spade.tasks : Object

/*
 * Some shortcuts to internal modules.
 */

/*
 * Cocker module that inherits from net.Socket.
 */
Spade.socket : Cocker

/*
 * Parser module, it could be an instance of Hiboris, a module
 * wrapper for the hiredis native parser, or the Boris JS parser.
 */
Spade.parser : Hiboris | Boris

/*
 * Libra Queue Manager for Commands/Replies bindings.
 */
Spade.queue : Libra

/*
 * Property that contains all mix-ins for the current semantic
 * version specified. Spade default value is false, interpreted
 * as '*'.
 *
 * NOTE: Specifying a particular semver version enables develop
 * mode, some mix-ins will be added to get infos about commands.
 * See Syllabus module for some examples.
 */
Spade.mixins : Syllabus

/*
 * A property that holds LUA commands and Cache, a shortcut
 * for Spade.mixins.lua.
 * See https://github.com/rootslab/syllabus#properties-methods.
 */
Spade.lua : Object

/*
 * Current cache property, an instance of Camphora.
 *
 * NOTE: the LUA script cache remains hidden until you explicitly
 * call the #initCache method.
 */
Spade.lua.cache : Camphora

/*
 * Cucu module to handle tasks.
 * See https://github.com/rootslab/cucu
 */
Spade.qq : Cucu

/*
 * A property that holds iterators for commands like SCAN, HSCAN, SSCAN, ZSCAN,
 * loaded with Spade#loadIterators.
 */
Spade.iterators : Object

/*
 * Debug Properties
 */

/*
 * Gerry module to handle events logging.
 * See https://github.com/rootslab/gerry
 */
Spade.logger : Gerry

Back to ToC


Methods

Arguments within [ ] are optional.

cli

Enable event logging to console.

This method enables/logs some extra event for debugging/testing purpose:

  • reply for Redis replies.
  • scanqueue when the "offline" command queue is processed.
  • queued for commands executed when the client is offline.

NOTE:

  • the 'enable' option defaults to true.
  • the 'logger' fn gets event name and event arguments.
Spade#cli( [ Boolean enable [, Function logger [, Boolean collect_events ] ] ] ) : undefined

See "Other Debug Events" section.

Back to ToC


connect

Open a connection to the Redis Server:

  • When the connection is fully established, the ready event will be emitted.
  • You can optionally use a callback that will be executed on the ready event.
  • It accepts an optional socket confguration object.
  • It returns the current Spade instance.

NOTE: You don't need to listen for the ready event, commands will be queued in "offline mode" and written to socket when the connection will be ready.

/*
 * socket_opt = {
 *      address : {
 *          host : '127.0.0.1'
 *          , port : 6379
 *      }
 *      , reconnection : {
 *          trials : 3
 *          , interval : 1000
 *      }
 *      , connection : {
 *          ...
 *      }
 *  }
 */
Spade#connect( [ Object socket_opt [, Function cback ] ] ) : Spade

Back to ToC


disconnect

Disconnect client from the Redis Server:

  • You can optionally use a cback that will be executed after socket disconnection.
  • It returns the current Spade instance.

NOTE: From the client point of view, executing disconnect has the same effect of sending and executing the Redis QUIT command. Connection will be closed and no other re-connection attempts will be made.

Spade#disconnect( [ Function cback ] ) : Spade

Back to ToC


initCache

Initialize or reveal the (hidden) LUA script cache:

  • It loads and sends all the files found in the ./node_modules/syllabus/lib/lua/scripts directory, to the Redis Server, always after the ready event.
  • It triggers cacheinit, cacheload, cacheready and scriptfailure events.
  • Optionally you could specify:
    • a custom loading path with something like : { filepath : '/my/scripts/dir' }.
    • a custom init configuration for the Camphora costructor to (re)build the cache.
    • a cback that will be executed on cacheready passing the current cache instance as argument.

NOTE: Empty files and scripts, processed and then refused by Redis with an error reply, are automatically evicted from the cache.

NOTE: If cache_opt is already set, the cache will be re-initialized; it happens only if the cache is ready, or when no other script commands are already been queued and not yet been sent to Redis (for example, when the client is offline); otherwise the cache will remain intact and an Error will be passed to the callback as the first argument.

/*
 *  Default values for 'cache_opt' are:
 *  {
 *    capacity : 128
 *    , encrypt_keys : false
 *    , algorithm : 'sha1'
 *    , output_encoding : 'hex'
 *    , input_encoding : 'binary'
 *  }
 */
Spade#initCache( [ Object f_opt [, Object cache_opt, [ Function cback ] ] ] ) : undefined

See Camphora#load for a list of available options for cache.

See "Script Cache Events" Section for the list of events.

Back to ToC


initTasks

Load methods/tasks from 'spade/lib/tasks' directory. It returns the current Spade.tasks property (or Cucu.ttable).

// filenames should be without '.js' extension.
Spade#initTasks( [ Array file_list ] ) : Object
polling task

For default, the 'connection.js' file exports/adds a single polling method to tasks. When polling is enabled, the client starts to PING server every 60 secs; it could be useful for testing connection aliveness, when the client is in PubSub mode.

Start the polling task:

Spade.tasks.polling.run( [ Number interval [, Array polling_fn_args [, Number times ] ] ] ) : Number

the polling method could receive 4 optional arguments, through the polling_fn_args Array:

pollingFn : function ( [ Function cback [, String ping_msg [, Number timeout [, Boolean reconnect ] ] ] ] )

for example:

/*
 * Pinging server every 2 seconds, with a 'BANG!' message and stop after 10 times.
 * For every reply received client emits 'polling' event.
 * If no reply will be received within 1 sec, client emits the 'hangup' event, then
 * disconnects and reconnects to the server.
 */
 var client = require( 'spade' )()
 ...
 client.cli();
 client.connect();
 ...
 client.initTasks();

 client.tasks.polling.run( 2000, [ null, 'BANG!', 1000, true ], 10 );
 ...
 client.task.polling.stop();
 ..

NOTE:

  • executing #initTasks, automatically enables/adds the polling and hangup events.
  • when in PubSub mode, the rollback mechanism doesn't save PINGs sent by the polling task.

See Tasks Events.

See Cucu to see all available options to handle tasks.

See polling tests.

Back to ToC


loadIterators

Load default iterators, for commands like SCAN, SSCAN, HSCAN, ZSCAN, from 'spade/lib/iterators' dir, you could restrict files to load, specifying some filenames without '.js' extension, for example: [ 'scan' ].

Spade#loadIterators( [ Array file_list ] ) : Object

It returns the current Spade.iterators property filled with:

Spade.iterators : {
   scan : function ( Number cursor [, Object opt [, Function cback ] ] ) : Object
   , hscan: function ( String key, Number cursor [, Object opt [, Function cback ] ] ) : Object
   , sscan: function ( String key, Number cursor [, Object opt [, Function cback ] ] ) : Object
   , zscan : function ( String key, Number cursor [, Object opt [, Function cback ] ] ) : Object
}

// you could use #next outside the callback to receive other results.
Object : { next : Function }

// default options for iterator commands:
opt : { match : null, count : 10 }

// 'cback' gets 3 arguments, you could call 'iterate' function inside the callback to receive next results.
cback : function ( Boolean is_err_reply, Array reply, Function iterate )

// reply Array for SCAN command:
reply : [ Boolean is_last_iter, Array keys, Number iter_counter, Number keys_counter ]

// for HSCAN, SSCAN, ZSCAN commands, the last element is the current hash/set/zset key being scanned.
reply : [ Boolean is_last_iter, Array keys, Number iter_counter, Number keys_counter, String key ]

NOTE:

  • signatures are the same as for relative Spade.commands, but they returns iterator objects.
  • when console logging is enabled with Spade#cli, 3 additional debug events will be added:
    • scan
    • sscan
    • hscan
    • zscan

See scan example.

See iterators events.

Back to ToC


Redis Commands

The Spade.commands property contains all methods to encode and send Redis commands, via the Syllabus module.

Brief List of Redis Command Types:

See Syllabus Commands Section for all signatures and available commands.

Command Callback

Every command mix-in accepts a callback function as the last argument, it will get 3 arguments:

/*
 * 'is_err_reply' is a Boolean that signals an ERROR reply from Redis,
 * ( not a JS Error ), then reply data will contain the error message(s).
 *
 * 'data' is a list containing reply data Buffers ( or Strings if hiredis is used ).
 *
 * 'reveal' is a utility function that converts the raw Redis Reply in a simple
 * and usable form.
 *
 * NOTE: The utility function is not the same for all command replies, because,
 * as we surely know, some reply needs particular format and type conversions.
 */
'callback' : function ( Boolean is_err_reply, Array data, Function reveal ) : undefined

Example Code:

var log = console.log
    , Spade = require( 'spade' )
    , client = Spade( {} )
    ;

// start async connection to Redis
client.connect();

// execute TIME command
client.commands.time( function ( is_err_reply, reply_data_arr, reveal_fn ) {
    log( '- error reply:', is_err_reply );
    log( '- raw reply:', reply_data_arr );
    log( '- converted reply:', reveal_fn( reply_data_arr ) );
} );

Back to ToC

Interactive Mode

Specifying a semver option ( like * or 1.0.0 ) enables Syllabus development mode for commands.

Example Code for REPL

$ cd spade/
$ node

# you can directly load the interactive example file executing:
# > cd spade/example
# > .load repl-example.js

# create a client instance with all commands (*)
> var client = require( './' )( { semver : '*' } )
..
# enable automatic console logging for events
> client.cli()
..
# get info about a command via mixins (Syllabus) property
> client.mixins.info('CoNfiG')

{ req: 'CoNfiG',
  name: 'config',
  args: -1,
  type: 'server',
  cmd: 'CONFIG',
  sub: 
   [ 'GET',
     'RESETSTAT',
     'REWRITE',
     'SET' ] }

# you can also stick the #info method to all available commands
> client.mixins.stick()

..returns a number..

# now get info about a method/command
> client.commands.ping.info()

{ req: 'ping',
  name: 'ping',
  args: 0,
  type: 'connection',
  cmd: 'PING',
  sub: [],
  url: 'http://redis.io/commands/ping',
  rtype: '+',
  since: '1.0.0',
  hint: 'PING',
  descr: 'Ping the server.' }

# now get info about a nested method/command
> client.commands.pubsub.numpat.info()

{ req: 'pubsub numpat',
  name: 'pubsub.numpat',
  args: 0,
  type: 'pubsub',
  cmd: 'PUBSUB NUMPAT',
  sub: [],
  url: 'http://redis.io/commands/pubsub',
  rtype: ':',
  since: '2.8.0',
  hint: 'PUBSUB NUMPAT',
  descr: 'Returns the total number of patterns all the clients are subscribed to.' }

# ok stop, now execute the command
> client.commands.pubsub.numpat()

!queued: [ { bulks: 2,
    cmd: 'PUBSUB',
    ecmd: '*2\r\n$6\r\nPUBSUB\r\n$6\r\nNUMPAT\r\n',
    fn: [Function],
    zn: [Function] },
  1 ]

# ops, command is not sent but queued, then open client connection..
> client.connect()
..
# read your reply, then quit or disconnect
> client.commands.quit()
..

See Syllabus Properties and Methods Section and repl-example.js.

Back to ToC

LUA Cache and SCRIPT Methods

Manually execute scripts commands, differently from Spade.commands.script methods, Spade.lua.script will also update the hidden cache for LUA scripts.

NOTE: these mix-ins are used internally by the initCache method , for loading script files and for revealing the hidden LUA cache.

Spade.lua.script property
/*
 * Get a script from the cache and send it to Redis.
 * It executes an EVALSHA command with the digest of the current script,
 * if it already exists.
 */
#run( String name, Array keys, Array args [, Function cback ] ) : undefined
 
/*
 * Manually load a script into the cache and send it to Redis.
 * It executes a SCRIPT LOAD command. 'lback' function will be called with an
 * argument that represents the entry loaded in the cache, or undefined if an
 * error occurs.
 */
#load( String key, String data [, Function cback [, Function lback ] ] ) : undefined
 
/*
 * Clear Spade and Redis cache. It executes a SCRIPT FLUSH command.
 * 'fback' function will be called with the number of elements flushed from the
 * cache.
 */
#flush( [ Function cback [, Function fback ] ] ) : undefined

See Syllabus.lua.

Back to ToC


Events

Events Sequence Diagram

  • the event emitted for first could be: - connect or offline, after the execution of connect or disconnect methods. - cacheinit, after the execution of initCache method. - error, it "simply" happens.
                             +                                     +
                             |                                     |
                             v                                     v
                          connect+------->(timeout)              error
                             +
                             |
                             +-------->(authorized)                +
                             |               +                     |
                             V               |                     v
              +         (authfailed)   +-----+-----+          (cacheinit)
              |              +         |           |               +
              v              |         v           v               |
  +------->offline<----+-----+----+(dbfailed) (dbselected)         |
  |           +        |     |                     +               |
  |           |        |     |                     |               |
  +           v        |     |                     v               |
lost<----+(*attempt*)  |     +------------------+ready+------------+
  +           +        |                           +               |
  |           |        +--+(*monitor*)<--+         |               v
  |           |                          |         |      +--------+-------+
  +->connect<-+                          +---------+      |                |
        +                                |                v                v
        |                   (listen)<----+        (*scriptfailure*)   (*cacheload*)
        v                       +                         +                +
       ...                      |                         |                |
                                v                         +--------+-------+
                           (*message*)+--->(shutup)                |
                                                                   v
                                                              (cacheready)

NOTE:

  • events between ( ) could never happen, most of them depends on client configuration.
  • events within * could be emitted more than once, namely 0 or k times with k >= 1.
  • timeout could happen in "any" moment after the connect event.
  • listen signals that client is entering in subscription mode
  • shutup signals that client is (voluntarily) leaving subscription mode.
  • monitor mode could end only with a QUIT command (then 'offline').

Back to ToC

Error Events

/*
 * A parser or command encoding error has occurred.
 */
'error' : function ( Error err, Object command )

Auth Events

These events are emitted on every client (re)connection to Redis and only if AUTH is set to be mandatory for the current connected host; namely, should exist an entry, 'ip:port' or '/path/to/file', in the options.security hash, with requirepass property set to a non empty string.

/*
 * The reply to AUTH command is an Error, then client will be disconnected;
 * it also happens when AUTH is not required by Redis but issued by the client.
 * No 'ready' event could be launched.
 */
'authfailed' : function ( String password, Array reply, Object address )

/*
 * Client authorization was successful. After that, the command queue will be
 * processed and the 'ready' event could be launched.
 */
'authorized' : function ( String password, Array reply, Object address )

Back to ToC

Select Events

These events are emitted on every client (re)connection to Redis. If the db property is set ( >== 0 ) in the options.security hash, for the current connected Redis host, the SELECT db command will be sent before all the other commands already present in the queue.

NOTE: When Redis needs authentication, SELECT command will be sent only after having sent the AUTH command and having received a successful reply from Redis.

/*
 * The reply to SELECT command is an Error, then client will be disconnected.
 * No 'ready' event could be launched.
 */
'dbfailed' : function ( String db, Array reply, Object address )

/*
 * Client authorization is successful. Now the command queue will be processed,
 * the 'ready' event could be launched.
 */
'dbselected' : function ( String db, Array reply, Object address )

Back to ToC

Script Cache Events

/*
 * Cache was initialized, script files are loaded in memory and a list
 * of SCRIPT LOAD commands are ready to be written to the socket.
 * Now that script commands are queued, it is possible to use and send
 * these and other commands.
 */
'cacheinit' : function ( Array script_load_commands )

/*
 * A script was processed and refused by Redis with an error reply.
 * Errored scripts are not added to local cache.
 */
'scriptfailure' : function ( String script_name, String error_message )

/*
 * A script was loaded in the cache and was successfully processed by Redis.
 */
'cacheload' : function ( String script_name, Buffer data, String txt )

/*
 * All scripts, found in the Syllabus scripts directory, are written to socket
 * and processed by Redis.
 *
 * NOTE: 'cacheready' event happens always after the 'ready' connection event,
 * because all scripts should be processed by Redis before launching this event.
 *
 * NOTE: cache for LUA scripts is an instance of Camphora module.
 */
'cacheready' : function ( Camphora lua_script_cache )

Back to ToC

Socket Connection Events

/*
 * After that the client has established a connection to the Redis host,
 * it is now ready to write commands to the socket and to receive the
 * relative replies from Redis. It happens after processing AUTH and
 * SELECT commands and finally the offline queue.
 *
 * NOTE: Every commands executed by the client before the 'ready' event,
 * will be enqueued in 'offline mode' and sent/written to socket when
 * 'ready' will be emitted.
 */
'ready' : function ( Object address, Number queued_command_sent )

/*
 * A client connection is fully established with Redis host. This event
 * happens before 'ready' and AUTH/SELECT related events.
 */
'connect' : function ( Object address )

/*
 * Connection is currently down ( on the first 'close' event from the socket ).
 */
'offline' : function ( Object address )

/*
 * Client is trying to reconnect to Redis server, k is the number of current
 * connection attempt.
 *
 * NOTE: 'millis' indicates the last interval of time between attempts.
 */
'attempt' : function ( Number k, Number millis, Object address )

/*
 * The connection is definitively lost ( after opt.reconnection.trials times ).
 */
'lost' : function ( Object address )

/*
 * The socket times out for inactivity.
 * It only notifies that the socket has been idle.
 */
'timeout' : function ( Number timeout,  Object address )

Back to ToC

PubSub Events

NOTE: for multiple (P)(UN)SUBSCRIBE commands, callbacks are executed one time for every message reply, those messages will be received also through the Pub/Sub system. However the first callback signals that the command is succesfully processed by Redis.

For example:

  • subscribe( [ 'a', 'a', 'b', 'b', 'c', 'c' ], cback ) :
    • executes callback 6 times
    • produces 6 messages
    • 3 actual subscriptions
  • unsubscribe( null, cback ):
    • executes cback 3 times
    • produces 3 messages
    • 0 subscriptions.
/*
 * A message was received through the PubSub system when the client
 * is in PubSub mode.
 *
 * NOTE: the 'formatter' function converts the received 'message' to
 * an obj/hash.
 * For example, a message reply to a (P)(UN)SUBSCRIBE command issued
 * by the client, could be:
 *
 * 'message' -> [ 'unsubscribe', 'channel', 0 ]
 *
 * will be converted to:
 *
 * {
 *  type : 'unsubscribe'
 *  , chan : 'channel'
 *  . subs : 0
 * }
 *
 * a typical message received from publisher(s):
 *
 * 'message' -> [ 'message', 'channel', 'Hello folks!' ]
 *
 * will be converted to:
 *
 * {
 *  type : 'message'
 *  , chan : 'channel'
 *  . msg : 'Hello folks!!'
 * }
 *
 * See also Syllabus.formatters.
 *
 */
'message' : function ( Array message, Function formatter )

/*
 * An event to signal that the client is entering in PubSub mode after a
 * subscription command. From now, all replies to (un)subscription commands
 * will be received as messages.
 */
'listen' : function ()

/*
 * An event to signal that client is leaving PubSub mode after a successfull
 * execution of a unsubscription command.
 * It doesn't happen if the client disconnects while in PubSub mode.
 */
'shutup' : function ()

Back to ToC

Monitor Events

/*
 * A 'message' was received when the client is in Monitor mode.
 * 
 * NOTE: the 'formatter' function converts the 'message' to an obj/hash.
 * For example, with an input like:
 *
 * message = '1405478664.248185 [0 127.0.0.1:47573] "ping"',
 *
 * executing formatter( message ) will output:
 *
 * {
 *  ip: '127.0.0.1',
 *  port: 47573,
 *  db: 0,
 *  cmd: '"ping"',
 *  utime: 1405478664248,
 *  time: [ 1405478664, 248185 ]
 * }
 *
 * See also Syllabus.formatters.
 *
 */
'monitor' : function ( String message, Function formatter )

Back to ToC

Tasks Events

NOTE: to enable logging for events below, execute Spade#initTasks method.

polling events
/*
 * polling event will be emitted every time a reply for PING will be received.
 */
'polling' : function ( Number is_pubsub_active, Number is_monitor_active )

/*
 * When the client doesn't receive a reply within the timeout interval specified
 * with Spade.tasks.polling#run, it disconnects from server, and optionally
 * reconnects.
 */
'hangup' : function ( Number is_pubsub_active, Number is_monitor_active )

See polling task.

Other Debug Events

NOTE: to enable logging for debug events , execute Spade#cli method.

/*
 * When the client is offline, commands are not sent but queued.
 */
'queued' : function ( Object command, Number offline_queue_size )

/*
 * When the client will be online once again, this event is emitted
 * before performing a scan for sending enqueued commands, then always
 * before the 'ready' event.
 */
'scanqueue' : function ( Number offline_queue_size )

/*
 * The client receives a command reply from Redis. It always happens after
 * the 'ready' event.
 */
'reply' : function ( Object command, String reply )

/*
 * The client receives an error reply from Redis. It always happens after
 * the 'ready' event.
 */
'error-reply' : function ( Object command, String err_reply )
iterators events

NOTE: to enable logging for events below, execute also Spade#loadIterators method.

'scan' : function ( Boolean is_last_iter, Number iterations, Number keys_counter )
'hscan' : function ( Boolean is_last_iter, Number iterations, Number keys_counter, String key )
'sscan' : function ( Boolean is_last_iter, Number iterations, Number keys_counter, String key )
'zscan' : function ( Boolean is_last_iter, Number iterations, Number keys_counter, String key )

See #loadIterators.

Back to ToC


MIT License

Copyright (c) 2014-present < Guglielmo Ferri : 44gatti@gmail.com >

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.