drogon
drogon copied to clipboard
Synchronous Redis Interface
Is your feature request related to a problem? Please describe. For Postgres, there is a synchronous interface to be able to wait for a response. This is important if you want to handle the response first before you return a response in the controller itself. For example, if you can't use co-routines or don't wan't to fall into the callback hell.
Describe the solution you'd like The solution I would like to see is a synchronous interface when setting off a redis request.
Describe alternatives you've considered Currently I use a custom solution with condition variables, which works, but it's weird that I have to do it myself.
We will consider this.
BTW, how did you use RedisResult out side the callback? The hiredis documentation says you can't do that. https://github.com/redis/hiredis/blob/d5b4c69b7113213c1da3a0ccbfd1ee1b40443c7a/README.md?plain=1#L372-L374
If the reply for a command with a NULL callback is read, it is immediately freed. When the callback for a command is non-NULL, the memory is freed immediately following the callback: the reply is only valid for the duration of the callback.
I didn't. Inside of the callback I'm justing moving the result string out of the RedisResult object to a variable outside of the callback. This is my current workaround to get a synchronous redis request:
std::optional<std::string> SessionsDB::execRedisCommandSync(const std::string& command)
{
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
std::condition_variable commandFinished;
std::optional<std::string> result;
redis->execCommandAsync(
[&](const drogon::nosql::RedisResult& r) {
if (!r.isNil())
result = r.asString();
commandFinished.notify_all();
},
[](const std::exception& e) {
throw e;
},
command
);
commandFinished.wait(lock);
return result;
}
Here is the reason why there isn't sync interfaces for redis in drogon.
In drogon, sync interfaces for pg and mysql are simulated by using async interfaces with a blocking operation (such as future.get()). However, as I mentioned above, we can not do this for redis. Hiredis doesn't allow us to hold a response object outside the async callback. So we must use hiredis sync interfaces to achieve that.
Currently, integrating hiredis sync interfaces is not of high priority for us, because:
- It needs lots of code structure changes.
- We already have coroutine, which has the same code flow as sync interface.
- Using sync interfaces will only cause performance drop, which is quite contradictory against the purpose of using c++ web framework.
If hiredis provides a way to access response object outside async callback in future, we will provide sync interfaces based on that.
Hope you understand us.
#1216 What about this solution?