Merge pull request #1074 from michael-grunder/kristjanvalur-pr4
Improved async documentation
This commit is contained in:
commit
c78d0926bf
89
README.md
89
README.md
@ -320,23 +320,48 @@ Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The
|
|||||||
should be checked after creation to see if there were errors creating the connection.
|
should be checked after creation to see if there were errors creating the connection.
|
||||||
Because the connection that will be created is non-blocking, the kernel is not able to
|
Because the connection that will be created is non-blocking, the kernel is not able to
|
||||||
instantly return if the specified host and port is able to accept a connection.
|
instantly return if the specified host and port is able to accept a connection.
|
||||||
|
In case of error, it is the caller's responsibility to free the context using `redisAsyncFree()`
|
||||||
|
|
||||||
*Note: A `redisAsyncContext` is not thread-safe.*
|
*Note: A `redisAsyncContext` is not thread-safe.*
|
||||||
|
|
||||||
|
An application function creating a connection might look like this:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
void appConnect(myAppData *appData)
|
||||||
if (c->err) {
|
{
|
||||||
|
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||||
|
if (c->err) {
|
||||||
printf("Error: %s\n", c->errstr);
|
printf("Error: %s\n", c->errstr);
|
||||||
// handle error
|
// handle error
|
||||||
|
redisAsyncFree(c);
|
||||||
|
c = NULL;
|
||||||
|
} else {
|
||||||
|
appData->context = c;
|
||||||
|
appData->connecting = 1;
|
||||||
|
c->data = appData; /* store application pointer for the callbacks */
|
||||||
|
redisAsyncSetConnectCallback(c, appOnConnect);
|
||||||
|
redisAsyncSetDisconnectCallback(c, appOnDisconnect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The asynchronous context can hold a disconnect callback function that is called when the
|
|
||||||
connection is disconnected (either because of an error or per user request). This function should
|
The asynchronous context _should_ hold a *connect* callback function that is called when the connection
|
||||||
|
attempt completes, either successfully or with an error.
|
||||||
|
It _can_ also hold a *disconnect* callback function that is called when the
|
||||||
|
connection is disconnected (either because of an error or per user request). Both callbacks should
|
||||||
have the following prototype:
|
have the following prototype:
|
||||||
```c
|
```c
|
||||||
void(const redisAsyncContext *c, int status);
|
void(const redisAsyncContext *c, int status);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On a *connect*, the `status` argument is set to `REDIS_OK` if the connection attempt succeeded. In this
|
||||||
|
case, the context is ready to accept commands. If it is called with `REDIS_ERR` then the
|
||||||
|
connection attempt failed. The `err` field in the context can be accessed to find out the cause of the error.
|
||||||
|
After a failed connection attempt, the context object is automatically freed by the libary after calling
|
||||||
|
the connect callback. This may be a good point to create a new context and retry the connection.
|
||||||
|
|
||||||
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
|
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
|
||||||
user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
|
user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
|
||||||
field in the context can be accessed to find out the cause of the error.
|
field in the context can be accessed to find out the cause of the error.
|
||||||
@ -344,12 +369,45 @@ field in the context can be accessed to find out the cause of the error.
|
|||||||
The context object is always freed after the disconnect callback fired. When a reconnect is needed,
|
The context object is always freed after the disconnect callback fired. When a reconnect is needed,
|
||||||
the disconnect callback is a good point to do so.
|
the disconnect callback is a good point to do so.
|
||||||
|
|
||||||
Setting the disconnect callback can only be done once per context. For subsequent calls it will
|
Setting the connect or disconnect callbacks can only be done once per context. For subsequent calls the
|
||||||
return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
|
api will return `REDIS_ERR`. The function to set the callbacks have the following prototype:
|
||||||
```c
|
```c
|
||||||
|
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||||
```
|
```
|
||||||
`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
|
`ac->data` may be used to pass user data to both of thes callbacks. An typical implementation
|
||||||
|
might look something like this:
|
||||||
|
```c
|
||||||
|
void appOnConnect(redisAsyncContext *c, int status)
|
||||||
|
{
|
||||||
|
myAppData *appData = (myAppData*)c->data; /* get my application specific context*/
|
||||||
|
appData->connecting = 0;
|
||||||
|
if (status == REDIS_OK) {
|
||||||
|
appData->connected = 1;
|
||||||
|
} else {
|
||||||
|
appData->connected = 0;
|
||||||
|
appData->err = c->err;
|
||||||
|
appData->context = NULL; /* avoid stale pointer when callback returns */
|
||||||
|
}
|
||||||
|
appAttemptReconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void appOnDisconnect(redisAsyncContext *c, int status)
|
||||||
|
{
|
||||||
|
myAppData *appData = (myAppData*)c->data; /* get my application specific context*/
|
||||||
|
appData->connected = 0;
|
||||||
|
appData->err = c->err;
|
||||||
|
appData->context = NULL; /* avoid stale pointer when callback returns */
|
||||||
|
if (status == REDIS_OK) {
|
||||||
|
appNotifyDisconnectCompleted(mydata);
|
||||||
|
} else {
|
||||||
|
appNotifyUnexpectedDisconnect(mydata);
|
||||||
|
appAttemptReconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Sending commands and their callbacks
|
### Sending commands and their callbacks
|
||||||
|
|
||||||
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
||||||
@ -382,6 +440,14 @@ valid for the duration of the callback.
|
|||||||
|
|
||||||
All pending callbacks are called with a `NULL` reply when the context encountered an error.
|
All pending callbacks are called with a `NULL` reply when the context encountered an error.
|
||||||
|
|
||||||
|
For every command issued, with the exception of **SUBSCRIBE** and **PSUBSCRIBE**, the callback is
|
||||||
|
called exactly once. Even if the context object id disconnected or deleted, every pending callback
|
||||||
|
will be called with a `NULL` reply.
|
||||||
|
|
||||||
|
For **SUBSCRIBE** and **PSUBSCRIBE**, the callbacks may be called repeatedly until a `unsubscribe`
|
||||||
|
message arrives. This will be the last invocation of the callback. In case of error, the callbacks
|
||||||
|
may reive a final `NULL` reply instead.
|
||||||
|
|
||||||
### Disconnecting
|
### Disconnecting
|
||||||
|
|
||||||
An asynchronous connection can be terminated using:
|
An asynchronous connection can be terminated using:
|
||||||
@ -394,6 +460,15 @@ have been written to the socket, their respective replies have been read and the
|
|||||||
callbacks have been executed. After this, the disconnection callback is executed with the
|
callbacks have been executed. After this, the disconnection callback is executed with the
|
||||||
`REDIS_OK` status and the context object is freed.
|
`REDIS_OK` status and the context object is freed.
|
||||||
|
|
||||||
|
The connection can be forcefully disconnected using
|
||||||
|
```c
|
||||||
|
void redisAsyncFree(redisAsyncContext *ac);
|
||||||
|
```
|
||||||
|
In this case, nothing more is written to the socket, all pending callbacks are called with a `NULL`
|
||||||
|
reply and the disconnection callback is called with `REDIS_OK`, after which the context object
|
||||||
|
is freed.
|
||||||
|
|
||||||
|
|
||||||
### Hooking it up to event library *X*
|
### Hooking it up to event library *X*
|
||||||
|
|
||||||
There are a few hooks that need to be set on the context object after it is created.
|
There are a few hooks that need to be set on the context object after it is created.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user