Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
47b57aa2
Commit
47b57aa2
authored
Mar 31, 2021
by
Kristján Valur Jónsson
Committed by
michael-grunder
Jun 26, 2022
Browse files
Add some documentation on connect/disconnect callbacks and command callbacks
parent
a890d9ce
Changes
1
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
47b57aa2
...
...
@@ -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.
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.
In case of error, it is the caller's responsibility to free the context using
`redisAsyncFree()`
*Note: A `redisAsyncContext` is not thread-safe.*
An application function creating a connection might look like this:
```
c
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
// handle error
void
appConnect
(
myAppData
*
appData
)
{
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
// 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:
```
c
void
(
const
redisAsyncContext
*
c
,
int
status
);
```
On a
*connect*
, the
`status`
argument is set to
`REDIS_OK`
if the connection attempted. 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
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.
...
...
@@ -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 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
return
`REDIS_ERR`
. The function to set the
disconnect
callback ha
s
the following prototype:
Setting the
connect or
disconnect callback
s
can only be done once per context. For subsequent calls
the
api will
return
`REDIS_ERR`
. The function to set the callback
s
ha
ve
the following prototype:
```
c
int
redisAsyncSetConnectCallback
(
redisAsyncContext
*
ac
,
redisConnectCallback
*
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 these this 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
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.
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
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
`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*
There are a few hooks that need to be set on the context object after it is created.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment