basiliscos / cpp-rotor Goto Github PK
View Code? Open in Web Editor NEWEvent loop friendly C++ actor micro-framework, supervisable
License: MIT License
Event loop friendly C++ actor micro-framework, supervisable
License: MIT License
If an actor reacts on some message type (response), when actor sends an request we'd like to invoke specific to the response handler.
One obvious solution will be to include request message into response, and do some if
in actor. Not very nice.
Another solution is to generate an new address, let the actor subscribes to the address, and let the actor sets this ephemeral address as reply_to
in the request. That works, however what about fail-case? Also if there is an undefined number of such req/res, how to manage them?
Some pattern should be developed in rotor::core
as address
contains non-owning pointer to a supervisor it might be case when the supervisor is shutdown and destroyed, and a message is sent to it => crash.
On the other hand, the client/server relationship between actors should be set up, and only after that the communication should be safe/reliable. In case of shutdown, "server" should notify "clients" about the shutdown and wait clients for "unsubscription" of the services, and only after that continue shutdown.
rationale: root supervisor provides execution context, meanwhile subsupervisor might inherit / share execution context with parent supervisor providing it's own supervising facilities.
For example: root EV-supervisor holds belongs to some thread and owns some loop. Subsupervisor might use the same thread/loop. In particular, messages to root supervisor will be delivered in synchronized manner, while for messages for sub-supervisors will be delivered the same manner as to regular actors.
Can we scale programs using rotor
across multiple servers and have actors able to find and communicate with each other? This is similar functionality to other actor frameworks, such as Orleans.
In my CMakeLists.txt
include( ExternalProject)
ExternalProject_Add(
rotor
GIT_REPOSITORY https://github.com/basiliscos/cpp-rotor.git
GIT_TAG master
PREFIX rotor
CMAKE_ARGS
-DBUILD_BOOST_ASIO=on
CMAKE_CACHE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/rotor
)
$ cmake --build build
[ 10%] Performing update step for 'rotor'
From https://github.com/basiliscos/cpp-rotor
7b23b99..925ade4 local-connect -> origin/local-connect
Current branch master is up to date.
Already up to date!
[ 20%] Performing configure step for 'rotor'
loading initial cache file /mnt/c/software/gitlab/raftlib/build/rotor/tmp/rotor-cache-Debug.cmake
-- Boost found.
-- Found Boost components:
date_time;system;regex
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/c/software/gitlab/raftlib/build/rotor/src/rotor-build
[ 30%] Performing build step for 'rotor'
Scanning dependencies of target rotor
[ 9%] Building CXX object CMakeFiles/rotor.dir/src/rotor/actor_base.cpp.o
[ 18%] Building CXX object CMakeFiles/rotor.dir/src/rotor/address_mapping.cpp.o
[ 27%] Building CXX object CMakeFiles/rotor.dir/src/rotor/behavior.cpp.o
[ 36%] Building CXX object CMakeFiles/rotor.dir/src/rotor/error_code.cpp.o
[ 45%] Building CXX object CMakeFiles/rotor.dir/src/rotor/message.cpp.o
[ 54%] Building CXX object CMakeFiles/rotor.dir/src/rotor/subscription.cpp.o
[ 63%] Building CXX object CMakeFiles/rotor.dir/src/rotor/supervisor.cpp.o
[ 72%] Building CXX object CMakeFiles/rotor.dir/src/rotor/system_context.cpp.o
[ 81%] Linking CXX static library librotor.a
[ 81%] Built target rotor
Scanning dependencies of target rotor_asio
[ 90%] Building CXX object CMakeFiles/rotor_asio.dir/src/rotor/asio/supervisor_asio.cpp.o
[100%] Linking CXX static library librotor_asio.a
[100%] Built target rotor_asio
[ 40%] Performing install step for 'rotor'
make[3]: *** No rule to make target 'install'. Stop.
CMakeFiles/rotor.dir/build.make:73: recipe for target 'rotor/src/rotor-stamp/rotor-install' failed
make[2]: *** [rotor/src/rotor-stamp/rotor-install] Error 2
CMakeFiles/Makefile2:72: recipe for target 'CMakeFiles/rotor.dir/all' failed
make[1]: *** [CMakeFiles/rotor.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
Sometimes it seems unclear why hierarchy is collapsing. It is obvious, that something happen, but not clear what is the root reason. So, when something go wrong, the shutdown message should setup error_code for easier examination of a supervisor.
In addition, when actor starts initialization, in the debug mode, it should print it's address and it's type. When it is going to down, it should also print it's type, address and the shutdown reason.
Seems not so complex to do.
The various actor-spawning pieces are scattered across API:
create_actor
The idea is to have an per-actor dedicated class (transferred per actor constructor) with the appropriate settings:
When trying to link to an aliased service (i.e. the same address is exposed via different names) multiple times (due to transparency of aliased names), assert triggers:
rotor/src/rotor/plugin/link_client.cpp:52: virtual void rotor::plugin::link_client_plugin_t::link(const address_ptr_t&, bool, const link_callback_t&): Assertion `servers_map.count(address) == 0' failed.
The work around to create additional addresses in the service, and alias self via different addresses, but this is not handy.
The API should be like:
using factory_t = std::function<r::actor_ptr_t(supervisor&)>;
enum class restart_policy_t {
always,
never,
transient // default
};
supervisor->lead(factory_t&&)
.restart(restart_policy_t)
.period(pt::milliseconds{500}) // 1 restart attempt per 500ms
.spawn() // spawn actor item now
by default supervisor starts spawning all herd, when it started, i.e. it is not affected by child death.
Refs:
https://www.erlang.org/doc/design_principles/sup_princ.html#tuning-the-intensity-and-period
if actor1 depends on actor2, actor2 should stay alive to allow actor1 operate correctly.
If actor2 is asked for shutting down, it should ask it's dependencies first (actor1)? Or it should just notify them that it is going down?
It seems that shutdown request should propagate down to the leafs in graph of actors, and let the leafs be shut down first?
Should the cycles in dependencies between actors be determined and notified, then? As the shutdown procedure seems impossible
Currently the order of messaging is preserved, i.e. when message m1
follows m2
, they will be processed by an actor as m1
, then m2
. This is correct, and what is expected.
However, them messages are sent to the same address, where actors (a1
and a2
), belong to supervisors but the same locality, are subscribed, they are processed in the following order (we assume that a1
subscribed "earlier" then a2
):
a1
processes m1
, then m2
, and then
a2
processes m1
and then m2
Generally speaking, this is correct, however this is not what is expected: using the same locality, means, that actors use the same thread (or same context), and can access to shared resources without synchronization. So, the expected order of processing should be:
a1
processes m1
a2
processes m1
a1
processes m2
a2
processes m2
It should be possible to spawn supervisor to work on pure thread
Looking at the interface for actors, it would be nice to remove the noise from the overridden methods, so that the code only deals with its own logic. It's cleaner that way.
Instead of this:
void on_start() noexcept override {
rotor::actor_base_t::on_start();
...
}
Have this, to eliminate the need to call rotor::actor_base_t::on_start()
:
class actor_base {
void base_on_start() {
// do base processing
// ...
on_start(); // Do overriding stuff.
}
virtual void on_start() {}
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.