Skip to content

Request must outlive async_exec? #215

Open
@bruno-viva

Description

@bruno-viva

First of all, thanks for this amazing library! It makes it very easy to integrate with Redis. Now onto the issue:

When calling async_exec, it is taking the request and keeping a pointer to it (in req_info). So a code like this:

void SetKey(std::string_view key, std::string_view value, boost::redis::connection& connection) {
  boost::redis::request request;
  request.push("SET", key, value);
  auto response = std::make_unique<boost::redis::response<std::string>>();
  auto& response_ref = *response;
  connection.async_exec(
      request, response_ref,
      [response = std::move(response)](const boost::system::error_code& error, std::size_t) {
        if (error) {
          std::cout << "Failed to send SET command to Redis server: " << error.what() << std::endl;
        } else {
          std::cout << "Response: " << std::get<0>(*response).value() << std::endl;
        }
      });
  // **Boom, request goes out of scope.**
}

Is invalid and has undefined behavior. I am using C++17, and so I prefer to not try the coroutines version.

I am not sure what the correct fix to the library is here (Should probably keep a copy of the request? Have const request& and request&& alternatives to copy/move the request in?). But I think the documentation could mention that, as it was not immediately obvious. In other words, the response is kind of obvious that needs to outlive it, but not the request! Some more C++17 examples would help too.

For completeness, here is a working version:

void SetKey(std::string_view key, std::string_view value, boost::redis::connection& connection) {
  auto request = std::make_unique<boost::redis::request>();
  request->push("SET", key, value);
  auto response = std::make_unique<boost::redis::response<std::string>>();
  auto& request_ref = *request;
  auto& response_ref = *response;
  connection.async_exec(
      request_ref, response_ref,
      [request = std::move(request), response = std::move(response)](const boost::system::error_code& error, std::size_t) {
        if (error) {
          std::cout << "Failed to send SET command to Redis server: " << error.what() << std::endl;
        } else {
          std::cout << "Response: " << std::get<0>(*response).value() << std::endl;
        }
      });
}

Thanks again for this lib! Looking forward to hearing your thoughts on this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions