Skip to content

async_exec now uses a sans-io strategy #250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from

Conversation

anarthal
Copy link
Collaborator

@anarthal anarthal commented May 12, 2025

async_exec now supports partial and total cancellation when the request is pending
Added docs on async_exec's cancellation support
Added detail::exec_fsm and macros for coroutine emulation
Requests are now removed from the multiplexer when an error is encountered

@anarthal anarthal marked this pull request as ready for review May 21, 2025 10:41
@anarthal anarthal marked this pull request as draft June 6, 2025 10:57
@anarthal
Copy link
Collaborator Author

anarthal commented Jun 7, 2025

Today is national's PR bombardment day :)

Quick walkthrough of this PR:

  • The main point is trying to split algorithms in async_compose into two parts, to make testing easier. The logic is extracted into a finite-state machine (exec_fsm in this case). The FSM is implemented as a coroutine. When the FSM needs to do something "non-local" (like invoking I/O, communicating with another task, etc), it yields, returning an action (exec_action in this case). The action contains all the information about what should be done. With this setup, exec_op becomes "dumb": it just invokes the FSM and executes the requested action.
  • In tests, we invoke the FSM directly, simulating different conditions, like cancellations. Tests are dead simple and reliable, but require a little bit of setup to simulate the right conditions (e.g. they create a multiplexer and invoke the functions that a reader and a writer would).
  • Ideally, I'd have used asio::coroutine for the FSM. However, this is implemented internally using __COUNTER__ on Windows, which causes trouble (see ODR violations when using asio::coroutine in header-only code under MSVC mysql#259 for an in-depth explanation). So I've created BOOST_REDIS_YIELD that does almost the same, but without this problem (I already use this everywhere in MySQL).
  • exec_action and exec_action_type create together a sort of Rust-like enum, to store what to do next. This is lighter at compile-time and easier to use than std::variant.
  • I've added a multiplexer::elem::is_done new status to track when something is done. This simplifies the algorithm.
  • The behavior on cancellation should almost match what we already had, with some fixes. For instance, calling reset_cancellation_state is required if we want to support cancellations other than terminal.
  • I've used Boost.Core lightweight_test instead of Boost.Test because it's lighter at compile time. I can revert to Boost.Test if you prefer it.
  • I've added some extra tests for cancellation, just in case.

@anarthal anarthal marked this pull request as ready for review June 7, 2025 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants