rotor is event loop friendly C++ actor micro framework,
sourcecraft
github
abf
telegram

- minimalistic loop agnostic core
- erlang-like hierarchical supervisors,
see this
and this
- various event loops supported (wx, boost-asio, ev) or planned (uv, gtk, etc.)
- asynchronous message passing interface
- request-response messaging with cancellation capabilities,
see
- MPMC (multiple producers multiple consumers) messaging, aka pub-sub
- cross-platform (windows, macosx, linux)
- inspired by The Reactive Manifesto and sobjectizer
| inter-thread (1) |
cross-thread (2) |
single thread (3) |
no alloc, TS (4) |
no alloc (5) |
| ~31.6M msgs/s |
~2.5M msgs/s |
~49.6М msgs/s |
~34.9M msgs/s |
~71.33M msgs/s |
Setup: Intel Core i7-1360P, Void Linux, 6.12.63
(1) Backend-independent; Can be measured with examples/boost-asio/ping-pong-single-simple, examples/ev/ping-pong-ev.
(2) Does not apply to wx-backend; can be measured with examples/thread/ping-pong-thread,
examples/boost-asio/ping-pong-2-threads, examples/ev/ping-pong-ev-2-threads.
(3) Backend-independent inter-thread messaging when build with ROTOR_BUILD_THREAD_UNSAFE=True. rotor objects (messages
and actors) cannot be accessed from different threads, cross-thread message sending facility cannot be used. This
option is mainly targeted for single-threaded apps.
(4) Thread-safe pre-allocated single message inter-thread ping-pong'ing, see examples/thread/ping-pong-no-alloc.cpp
using redirect() technique intoduced in v0.36 .
(5) Thread-unsafe (ROTOR_BUILD_THREAD_UNSAFE=True) pre-allocated single message inter-thread ping-pong'ing,
see examples/thread/ping-pong-no-alloc.cpp using redirect() technique intoduced in v0.36 .
MIT
Please read tutorial, design principles and manual here
Looking for something actor-flavored, but suitable for embedded applications?
Take a look into tardigrade project of
my friend or rotor-light.
To my opinion tardigrade is a bit better
designed and should be considered first.
- [bugfix] avoid race in registry plugin during shutdown
- [bugfix] avoid race in link_client plugin during shutdown
- [bugfix] avoid race in supervisor during requests discarding
- [doc] update synthetic performance metrics
- [bugfix] [thread-backend] decrease cpu usage
- [example] added examples/thread/ping-pong-no-alloc.cpp
(use message redirection/no alloctions)
- [cmake] copy compile_commands.json only for Makefile generator
- [ci] use sourcecraft hosting platform as CI/CD friendly
- [ci] fix appveyor windows builds
- [cmake, bugfix] export compile_commands.json only if cmake version is >= 3.29
(more correct fix, thanks to @ErniGH)
- [cmake, bugfix] export compile_commands.json only if cmake version is >= 3.29
- [feature, asio, thread, ev] allow poll-duration to be set to zero save CPU cycles/battery
- [cmake, breaking] increase cmake version requirement 3.15 -> 3.17
- [cmake] generate file for clangd langserv (thanks for @rymdbar)
- [cosmetic] removed trailing spaces (thanks for @rymdbar)
- [cosmetic] fixed identation to make sources more vim-folding friendly (thanks for @rymdbar)
- [cosmetic] configure linters to project style (thanks for @rymdbar)
- [feature] add route() and redirect() high-level actor methods, which
provide convenient API over make_routed_message() introduced in v0.32
- [breaking] asio supervisor uses steady clock instead of system clock (aka deadline_timer)
- [feature] improve c++20 support
- [workaround, fltk] more realiable message delivery for fltk backend. Fltk
might "forget" to invoke scheduled awakes after shutdown process, which leads
to minor memory leaks
- [cmake, breaking] use CMAKE_CURRENT_SOURCE_DIR instead of CMAKE_SOURCE_DIR
- [cmake, breaking] configure option renamed BUILD_BOOST_ASIO => ROTOR_BUILD_ASIO
- [cmake, breaking] configure option renamed BUILD_WX => ROTOR_BUILD_WX
- [cmake, breaking] configure option renamed BUILD_EV => ROTOR_BUILD_EV
- [cmake, breaking] configure option renamed BUILD_FLTK => ROTOR_BUILD_FLTK
- [cmake, breaking] configure option renamed BUILD_THREAD => ROTOR_BUILD_THREAD
- [cmake, breaking] configure option renamed BUILD_DOC => ROTOR_BUILD_DOC
- [cmake, breaking] configure option renamed BUILD_THREAD_UNSAFE => ROTOR_BUILD_THREAD_UNSAFE
- [cmake, new] configure option added ROTOR_BUILD_TESTS (instead of ENABLE_TESTING)
- [cmake, bugfix, win32] add ws2_32 lib for rotor_asio win32 build
- [feature] added make_routed_message() free function.
The function is used for "synchronized" message post-processing, i.e. once a
message has been delivered and processed by all recipients (can be zero),
then it is routed to the specifed address to do cleanup.
Example:
- an db-actor and opens transaction and reads data (i.e. as std::string_views, owned by db)
- actors sends broadcast message to all interesting parties to deserialized data
- after the step 2 is finished the db-actor closes transaction and releases acquired resources.
The make_routed_message is needed to perform recipient-agnostic 3rd step.
The alternative is to create a copy (snapshot) of data (i.e. std::string
instead of std::string_view), but that seems redundant.
- [improvement, breaking] add void* parameter to message_visitor_t
- [bugfix, fltk] more realiable message delivery for fltk backend
- [feature] added fltk-backend
- [feature, conan] enable_fltk option which add fltk-support
- [example] added /examples/ping-pong-fltk.cpp and
examples/ping-pong-fltk_and_thread.cpp
- [bugfix] wx-backend building and testing
- [improvement, breaking] output directories are set to bin for cmake
- [improvement, breaking] actor_base_t::make_error() is marked as const
- [bugfix] fix segfault in delivery plugin in debugging mode
(try to set env ROTOR_INSPECT_DELIVERY=99 to see)
- [cmake, bugfix] add missing header into installation
- [feature] new interface message_visitor_t
- [feature] new interface message_stringifier_t and the default implementation
default_stringifier_t which allows to dump messages. It is not a production but
a diagnostic/debug tool, due to performance restrictions.
- [feature] system_context_t provides a reference to default message_stringifier_t;
it is possible to have a custom one
- [feature, breaking] extended_error_t holds a reference to a request message,
which caused an error
- [examples, tests, win32] fix ev examples and tests
- [example] modernize examples/thread/sha512.cpp to use recent openssl version
- [breaking] cmake requirements are lowered to 3.15
- [breaking] fix minor compilation warnings
- [feature] start_timer callback not only method, but any invocable
- [feature, conan] enable_ev option which add libev
- [breaking, conan] boost minimum version 1.83.0
- [testing, conan] remove catch2 from sources and make it dependencies
- [bugfix, breaking] make plugins more dll-friendly
- [breaking] cmake minimum version 3.23
- [breaking] rename registry_t::revese_map_t revese_map -> registry_t::reverse_map_t reverse_map
- [breaking] rename struct cancelation_t -> cancellation_t
- [doc] fix multiple typos
- [bugfix] avoid response messages loose their order relative to regular message
- [bugfix, example] add missing header
- [feature] improve inter-thread messaging performance up to 15% by using boost::unordered_map
instead of std::unordered_map
- [bugfix, breaking] avoid introducing unnecessary event loops latency by intensive polling of
rotor queues; affects asio and ev loops
- [bugfix] registry_plugin_t, allow to discover aliased services (#46)
- [bugfix] fix compilation issues of messages.cpp on some platforms
- [bugfix, msvc] fix compilation issues of registry plugin for shared library
on msvc-16+
- [feature] possibly to install via conan center
- [feature, breaking] possibility to build rotor as shared library
- [feature] add shutdown flag checker (see my blog)
- [bugfix] requests do not outlive actors (i.e. they are cancelled on shutdown_finish)
- [example] there is my another open-source project syncspirit,
which uses rotor under hood. I recommend to look at it, if the shipped examples are too-trivial, and
don't give you an architectural insight of using rotor.
- [improvement] preliminary support of conan package manager
- [bugfix] fix compilation warnings on Windows/MSVC
- [bugfix] add missing header for rotor::thread installation
- [improvement] superviser can create spawner, which has a policy to auto-spawns
new actor instance if previous instance has been shutdown. This is similar to
escalate_failure supervising in erlang,
see dedicated article
- [improvement] actor can now autoshutdown_supervisor(), when it shutdown
- [improvement] actor can now escalate_failure(), i.e. trigger shutdown own supervisor
when it finished with failure
- [improvement] messages delivery order is persevered per-locality (see issue #41)
- [example] examples/thread/ping-pong-spawner (new)
- [example] examples/autoshutdown (new)
- [example] examples/escalate-failure (new)
- [documentation] updated Design principles
- [documentation] updated Examples
- [documentation] updated Introduction
- [improvement] performance improvement in inter-thread (+20%) and cross-thread messaging
- [bugfix] supervisor does not shut self down in rare conditions, when it fails to initialize self
- [bugfix] link_server plugin should ignore unlink_notifications
- [bugfix] avoid cycle (i.e. memleak) in rare cases when supervisor is shutdown, but an external
message arrives for processing
- [improvement] add static_assert for noexcept check of a hanler signature
- [improvement] add gitee mirror
- [bugfix] fix potential use-after-free in ev backend
- [bugfix] fix installation issues with cmake (thanks to @melpon)
- [bugfix] fix missing header (thanks to @melpon)
- [ci] drop travis-ci in the sake of circle-ci
- [improvement] significant message throughtput increase for std::thread, boost-asio
and ev backends (upto 5x times)
- [improvement] extended_error can now access to root reason
- [improvement] delivery plugin in debug mode dumps discovery requests and responses
- [improvement/breaking] more details on fatal error (system_context)
- [example] examples/thread/ping-pong-thread.cpp (new)
- [example] examples/ev/ping-pong-ev-2-threads (new)
- [bugfix] lifetime_plugin_t do not unsubscribe from foreign to me subscriptions
- [bugfix] foreigners_support_plugin_t more safely deliver a message for a foreign
subscriber (actor)
- the dedicated article with highlights: en and
ru
- [improvement] actor identity has been introduced. It can be configured or generated via
address_maker plugin
- [improvement] actor::do_shutdown() - optionally takes shutdown reason
- [improvement/breaking] instead of using std::error_code the extended_error class
is used. It wraps std::error_code, provides string context and pointer to the next
extended_error cause. This greatly simplifies error tracking of errors. Every response
now contains ee field instead of ec.
- [improvement] actor has shutdown reason (in form of extended_error pointer)
- [improvement] delivery plugin in debug mode it dumps shutdown reason in shutdown trigger
messages
- [improvement] actor identity has on_unlink method to get it know, when it has been
unlinked from server actor
- [improvement] add resources plugin for supervisor
- [breaking] all responses now have extended_error pointer instead of std::error_code
- [breaking] shutdown_request_t and shutdown_trigger_t messages how have
shutdown reason (in form of extended_error pointer)
- [bugfix] link_client_plugin_t do not invoke custom callback, before erasing request
in case of failure
- [bugfix] child_manager_plugin_t reactivate self if a child was created from other
plugin.
- [bugfix] registry actor incorrectly resolves postponed requests to wrong addresses
- [improvement] delivery plugin in debug mode dumps discarded messages
- [breaking] state_response_t has been removed
- [bugfix] allow to acquire & release resources in via resources_plugin_t, during
other plugin configuration
- [bugfix] foreigners_support_plugin_t did not deactivated self properly, caused
assertion fail on supervisor shutdown, when there was foreign subscriptions
- [bugfix] link_client_plugin_t did not notified linked server-actors, if its actor is
going to shutdown; now server-actors are requested to unlink
- [bugfix] starter_plugin_t sometimes crashed when subscription confirmation message
arrives when actor is in non-initializing phase (i.e. shutting down)
- [bugfix] root supervisor is not shutdown properly when it is linked as "server"
- [improvement] added std::thread backend (supervisor)
- [bugfix] active timers, if any, are cancelled upon actor shutdown finish
- [bugfix] supervisor shutdown message is lost in rare cases right after
child actor start
- [example] examples/thread/sha512.cpp (new)
- [documentation] updated Event loops & platforms
- [documentation] updated Patterns with Blocking I/O multiplexing
- [deprecated] state_response_t, state_request_t will be removed in v0.13
- [improvement] when supervisor shuts self down due to child init failure,
the supervisor init error code is "failure escalation"
- [documentation] updated Advanced examples,
- [bugfix] when actor shuts self down all its timers are properly
cancelled
- [bugfix] in rare case supervisor starts, event if child failed to init
- [bugfix] asio: more correct timers cancellation implementation
- [bugfix] ev: more correct shutdown (avoid memory leaks in rare cases)
- [improvement/breaking] Generic timers interface
- [improvement] Request cancellation support
- [improvement] added make_response methods when message should be created, but
send later delayed
- [improvement] more debug information in message delivery plugin
- [documentation] Integration with event loops
- [documentation] Requests cancellation and timers are demonstrated in the
Advanced Examples section
- [example] examples/boost-asio/ping-pong-timer.cpp (new)
- [example] examples/boost-asio/beast-scrapper.cpp (updated)
- [bugfix] avoid double configuration of a plugin in certain cases when interacting
with resources plugin
- [bugfix] more correct cmake installation (thanks to Jorge López Tello, @LtdJorge)
- the dedicated article with highlights: en and
ru
- [improvement] rewritten whole documentation
- [improvement/breaking] plugin system where introduced for actors instead of
behaviors
- [improvement] actor_config_t was introduced, which now holds pointer to
supervisor, init and shutdown timeouts
- [improvement] builder pattern was introduced to simplify actors construction
- [breaking] supervisor_config_t was changed (inherited from actor_config_t)
- [breaking] actor_base_t and supervisor_t constructors has changed - now
appropriate config is taken as single parameter. All descendant classes should
be changed
- [breaking] if a custom config type is used for actors/supervisors, they
should define config_t inside the class, and templated config_builder_t.
- [breaking] supervisor in actor is now accessible via pointer instead of
reference
- [bugfix] supervisor_ev_t not always correctly released EV-resources, which
lead to leak
- [bugfix] actor_base_t can be shutted down properly even if it did not
started yet
- [bugfix] message's arguments are more correctly forwarded
- [bugfix] actor's arguments are more correctly forwarded in actor's
creation inrotor::supervisor_t and rotor::asio::supervisor_asio_t
- [bugfix] rotor::asio::forwarder_t now more correctly dispatches
boost::asio events to actor methods; e.g. it works correctly now with
async_accept method of socket_acceptor
- [improvement] more modern cmake usage
- [improvement] registry actor was added to allow via name/address runtime
matching do services discovery
- [improvement, breaking] minor changes in supervisor behavior: now it
is considered initialized when all its children confirmed initialization
- [improvement] supervisor_policy_t was introduced to control supervisor
behavior on a child-actor startup failure
- [example] examples/ev/pong-registry.cpp how to use registry
- [doc] patterns/Registry was added
- [improvement] response can be inherited from rotor::arc_base, to allow
forwarding requests without copying it (i.e. just intrusive pointer is created)
- [example] examples/boost-asio/beast-scrapper.cpp has been added; it
demonstrates an app with pool of actor workers with request-response forwarding
- [improvement] the request-response approach is integrated to support basic
reliable messaging: response notification failure will be delivered,
if the expected response will not arrive in-time
- [improvement] lambda subscribers are supported
- [improvement] actor behavior has been introduced to offload actor's
interface
- [breaking] supervisor is constructed with help of supervisor_config_t,
which contains shutdown timeout value
- [breaking] supervisor does not spawns timeout timer for overall shutdown
procedure, instead per-child timers are spawned. The root supervisor
the same way monitors child-supervisor shut down
- [breaking] supervisor create_actor method now takes child max
init time value. If it does not confirm, the child actor will be asked
for shut down.
- [breaking] shutdown request sent to an child actor now timeout-tracked
by supervisor. The message type has changed to message::shutdown_request_t
- [breaking] init request sent to an child actor now timeout-tracked
by supervisor. The message type has changed to message::init_request_t
- [breaking] actor's state request message type now message::state_request_t,
which follows the generic request/response pattern. The response type
is now message::state_response_t.
- [breaking] {asio, ev, ws} supervisor configs are renamed to have
corresponding suffix.
- [improvement] locality notion was introduced, which led to possibility
to build supervising trees, see blog-cpp-supervisors
- [breaking] the outbound field in rotor::supervisor_t was renamed just to queue
- [breaking] rotor::address_t now contains const void* locality
- [breaking] rotor::asio::supervisor_config_t now contains
std::shared_ptr to strand, instead of creating private strand
for each supervisor
- [bugfix] redundant do_start() method in rotor::supervisor_t was
removed, since supervisor now is able to start self after completing
initialization.
- [bugfix] rotor::supervisor_t sends initialize_actor_t to self
to advance own state to INITIALIZED via common actor mechanism,
instead of changing state directly on early initialization phase
(do_initialize)
- [bugfix] rotor::asio::forwarder_t now more correctly dispatches
boost::asio events to actor methods
- [bugfix] rotor::ev::supervisor_ev_t properly handles refcounter