Redis has a few blocking commands among the built-in set of commands.
One of the most used is `BLPOP` (or the symmetric `BRPOP`) which blocks
waiting for elements arriving in a list.
The interesting fact about blocking commands is that they do not block
the whole server, but just the client calling them. Usually the reason to
block is that we expect some external event to happen: this can be
some change in the Redis data structures like in the `BLPOP` case, a
long computation happening in a thread, to receive some data from the
network, and so forth.
Redis modules have the ability to implement blocking commands as well,
this documentation shows how the API works and describes a few patterns
that can be used in order to model blocking commands.
How blocking and resuming works.
---
_Note: You may want to check the `helloblock.c` example in the Redis source tree
inside the `src/modules` directory, for a simple to understand example
on how the blocking API is applied._
In Redis modules, commands are implemented by callback functions that
are invoked by the Redis core when the specific command is called
by the user. Normally the callback terminates its execution sending
some reply to the client. Using the following function instead, the
function implementing the module command may request that the client
is put into the blocked state:
RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
The function returns a `RedisModuleBlockedClient` object, which is later
used in order to unblock the client. The arguments have the following
meaning:
*`ctx` is the command execution context as usually in the rest of the API.
*`reply_callback` is the callback, having the same prototype of a normal command function, that is called when the client is unblocked in order to return a reply to the client.
*`timeout_callback` is the callback, having the same prototype of a normal command function that is called when the client reached the `ms` timeout.
*`free_privdata` is the callback that is called in order to free the private data. Private data is a pointer to some data that is passed between the API used to unblock the client, to the callback that will send the reply to the client. We'll see how this mechanism works later in this document.
*`ms` is the timeout in milliseconds. When the timeout is reached, the timeout callback is called and the client is automatically aborted.
Once a client is blocked, it can be unblocked with the following API:
int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata);
The function takes as argument the blocked client object returned by
the previous call to `RedisModule_BlockClient()`, and unblock the client.
Immediately before the client gets unblocked, the `reply_callback` function
specified when the client was blocked is called: this function will
have access to the `privdata` pointer used here.
IMPORTANT: The above function is thread safe, and can be called from within
a thread doing some work in order to implement the command that blocked
the client.
The `privdata` data will be freed automatically using the `free_privdata`
callback when the client is unblocked. This is useful **since the reply
callback may never be called** in case the client timeouts or disconnects
from the server, so it's important that it's up to an external function
to have the responsibility to free the data passed if needed.
To better understand how the API works, we can imagine writing a command
that blocks a client for one second, and then send as reply "Hello!".
Note: arity checks and other non important things are not implemented
int his command, in order to take the example simple.
int Example_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,