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
Show 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
...
@@ -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 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
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.
...
@@ -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 callback
s
can only be done once per context. For subsequent calls
the
return
`REDIS_ERR`
. The function to set the
disconnect
callback ha
s
the following prototype:
api will
return
`REDIS_ERR`
. The function to set the callback
s
ha
ve
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 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
### 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.
...
@@ -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
...
@@ -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.
...
...
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