@@ -593,7 +593,7 @@ class basic_connection {
593593 return async_run (config{}, std::forward<CompletionToken>(token));
594594 }
595595
596- /* * @brief Receives server side pushes asynchronously.
596+ /* * @brief (Deprecated) Receives server side pushes asynchronously.
597597 *
598598 * When pushes arrive and there is no `async_receive` operation in
599599 * progress, pushed data, requests, and responses will be paused
@@ -623,12 +623,76 @@ class basic_connection {
623623 * @param token Completion token.
624624 */
625625 template <class CompletionToken = asio::default_completion_token_t <executor_type>>
626+ BOOST_DEPRECATED (" Please use async_receive2 instead." )
626627 auto async_receive(CompletionToken&& token = {})
627628 {
628629 return impl_->receive_channel_ .async_receive (std::forward<CompletionToken>(token));
629630 }
630631
631- /* * @brief Receives server pushes synchronously without blocking.
632+ /* * @brief Wait for server pushes asynchronously
633+ *
634+ * This function suspends until a server push is received by the
635+ * connection. On completion an unspecified number of pushes will
636+ * have been added to the response object set with @ref
637+ * boost::redis::connection::set_receive_response.
638+ *
639+ * To prevent receiving an unbound number of pushes the connection
640+ * blocks further read operations on the socket when 256 pushes
641+ * accumulate internally (we don't make any commitment to this
642+ * exact number). When that happens ongoing `async_exec`s and
643+ * health-checks won't make any progress and the connection will
644+ * eventually timeout. To avoid that Apps should call
645+ * `async_receive2` continuously in a loop.
646+ *
647+ * @Note To avoid deadlocks the task (e.g. coroutine) calling
648+ * `async_receive2` should not call `async_exec` in a way where
649+ * they could block each other.
650+ *
651+ * For an example see cpp20_subscriber.cpp. The completion token
652+ * must have the following signature
653+ *
654+ * @code
655+ * void f(system::error_code);
656+ * @endcode
657+ *
658+ * @par Per-operation cancellation
659+ * This operation supports the following cancellation types:
660+ *
661+ * @li `asio::cancellation_type_t::terminal`.
662+ * @li `asio::cancellation_type_t::partial`.
663+ * @li `asio::cancellation_type_t::total`.
664+ *
665+ * Calling `basic_connection::cancel(operation::receive)` will
666+ * also cancel any ongoing receive operations.
667+ *
668+ * @param token Completion token.
669+ */
670+ template <class CompletionToken = asio::default_completion_token_t <executor_type>>
671+ auto async_receive2 (CompletionToken&& token = {})
672+ {
673+ return
674+ impl_->receive_channel_ .async_receive (
675+ asio::deferred (
676+ [&conn = *this ](system::error_code ec, std::size_t )
677+ {
678+ if (!ec) {
679+ auto f = [](system::error_code, std::size_t ) {
680+ // There is no point in checking for errors
681+ // here since async_receive just completed
682+ // without errors.
683+ };
684+
685+ // We just want to drain the channel.
686+ while (conn.impl_ ->receive_channel_ .try_receive (f));
687+ }
688+
689+ return asio::deferred.values (ec);
690+ }
691+ )
692+ )(std::forward<CompletionToken>(token));
693+ }
694+
695+ /* * @brief (Deprecated) Receives server pushes synchronously without blocking.
632696 *
633697 * Receives a server push synchronously by calling `try_receive` on
634698 * the underlying channel. If the operation fails because
@@ -638,6 +702,7 @@ class basic_connection {
638702 * @param ec Contains the error if any occurred.
639703 * @returns The number of bytes read from the socket.
640704 */
705+ BOOST_DEPRECATED (" Please, use async_receive2 instead." )
641706 std::size_t receive(system::error_code& ec)
642707 {
643708 std::size_t size = 0 ;
@@ -837,7 +902,7 @@ class basic_connection {
837902 " the other member functions to interact with the connection." )
838903 auto const & next_layer() const noexcept { return impl_->stream_ .next_layer (); }
839904
840- // / Sets the response object of @ref async_receive operations.
905+ // / Sets the response object of @ref async_receive2 operations.
841906 template <class Response >
842907 void set_receive_response (Response& resp)
843908 {
@@ -1028,12 +1093,21 @@ class connection {
10281093
10291094 // / @copydoc basic_connection::async_receive
10301095 template <class CompletionToken = asio::deferred_t >
1096+ BOOST_DEPRECATED (" Please use async_receive2 instead." )
10311097 auto async_receive(CompletionToken&& token = {})
10321098 {
10331099 return impl_.async_receive (std::forward<CompletionToken>(token));
10341100 }
10351101
1102+ // / @copydoc basic_connection::async_receive2
1103+ template <class CompletionToken = asio::deferred_t >
1104+ auto async_receive2 (CompletionToken&& token = {})
1105+ {
1106+ return impl_.async_receive2 (std::forward<CompletionToken>(token));
1107+ }
1108+
10361109 // / @copydoc basic_connection::receive
1110+ BOOST_DEPRECATED (" Please use async_receive2 instead." )
10371111 std::size_t receive(system::error_code& ec) { return impl_.receive (ec); }
10381112
10391113 /* *
0 commit comments