Review of the latest changes in rotor (v0.10 ... v0.14)

actor system







rotor is an unobtrusive C ++ actor microformwork with the ability to create supervisor hierarchies, similar to its older brothers - caf and sobjectizer . In recent releases, since the last announcement , significant improvements have accumulated that I would like to highlight.







Common interface for timers (v0.10)



, . . . v0.10



API , ; (event loop) API, . : API , API rotor', . , , .







v0.10



rotor', - :







namespace r = rotor;

struct some_actor_t: r::actor_base_t {
    void on_start() noexcept {
        timer_request = start_timer(timeout, *this, &some_actor_t::on_timer);
    }

    void on_timer(r::request_id_t, bool cancelled) noexcept {
        ...;
    }

    void some_method() noexcept {
        ...
        cancel_timer(timer_id);
    }

    r::request_id_t timer_id;
};
      
      





, (shutdown_finish), , (undefined behavior).







(v0.10)



- , caf "-", sobjectizer' "--" ("fire-and-forget") . rotor , - "--", "-" .







, caf sobjectizer, , , , . , rotor' , , . "-" , "" , - (I/O), . , HTTP-, , . : , , , .







, , .. - , , - .







rotor', , , , - , , , , -, , , "". , - , . . .







namespace r = rotor;

namespace payload {
struct pong_t {};
struct ping_t {
    using response_t = pong_t;
};
} // namespace payload

namespace message {
using ping_request_t = r::request_traits_t<payload::ping_t>::request::message_t;
using ping_response_t = r::request_traits_t<payload::ping_t>::response::message_t;
using ping_cancel_t = r::request_traits_t<payload::ping_t>::cancel::message_t;
} // namespace message

struct some_actor_t: r::actor_base_t {
    using ping_ptr_t = r::intrusive_ptr_t<message::ping_request_t>;

    void on_ping(ping_request_t& req) noexcept {
        // just store request for further processing
        ping_req.reset(&req);
    }

    void on_cancel(ping_cancel_t&) noexcept {
        if (req) {
            // make_error is v0.14 feature
            make_response(*req, make_error(r::make_error_code(r::error_code_t::cancelled)));
            req.reset();
        }
    }

    //  ""   .
    ping_ptr_t ping_req;
};
      
      





, sobjectizer', , , -, "-", , -, , sobjectizer', . . . , - , "-" sobjectizer', , , , , .







std::thread backend/supervisor (v0.12)



, rotor sobjectizer: , . , .







, . , , . , ; , , , . , , , .. , , sha512 1TB, , . .







, std::thread



, . , , , rotor' , "" (), . , ..:







struct sha_actor_t : public r::actor_base_t {
    ...
    void configure(r::plugin::plugin_base_t &plugin) noexcept override {
        r::actor_base_t::configure(plugin);
        plugin.with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
            p.subscribe_actor(&sha_actor_t::on_process)->tag_io(); // 
        });
    }
      
      





, sha512



, CTRL+c



, .







(v0.14)



— ( rotor' , sobjectizer' mbox



'). , , , :







struct my_supervisor_t : public r::supervisor_t {
    void on_child_shutdown(actor_base_t *actor) noexcept override {
        std::cout << "actor " << (void*) actor->get_address().get() << " died \n";
    }
}
      
      





, . , , , , on_start()



. , , std::string identity



actor_base_t



. , address_maker_plugin_t



:







struct some_actor_t : public t::actor_baset_t {
    void configure(r::plugin::plugin_base_t &plugin) noexcept override {
        plugin.with_casted<r::plugin::address_maker_plugin_t>([&](auto &p) {
            p.set_identity("my-actor-name", false);
        });
        ...
    }
};
      
      





:







struct my_supervisor_t : public r::supervisor_t {
    void on_child_shutdown(actor_base_t *actor) noexcept override {
        std::cout << actor->get_identity() << " died \n";
    }
}
      
      





, . , . bool



set_identity(name, append_addr)



.







- actor 0x7fd918016d70



supervisor 0x7fd218016d70



. rotor' v0.14



.







Extended Error std::error_code, shutdown reason (v0.14)



- , v0.14



, std::error_code



. , , , rotor', . : , . , . . . , , , , , . , std::error_code



.







Therefore, it was decided to introduce our own extended error class rotor::extended_error_t



, which contains std::error_code



, std::string



as a context (usually the identity of the actor), as well as a smart pointer to the next extended error that caused the current one. Now the collapse of the actor hierarchy can be represented by a chain of extended errors, where the reason for the shutdown of each actor can be traced:







struct my_supervisor_t : public r::supervisor_t {
    void on_child_shutdown(actor_base_t *actor) noexcept override {
        std::cout << actor->get_identity() << " died, reason :: " << actor->get_shutdown_reason()->message();
    }
}
      
      





will output something like:







actor-2 due to supervisor shutdown has been requested by supervisor <- actor-1 due initialization failed
      
      





Together with actor identification, this feature provides more diagnostic tools for developers who use rotor .








All Articles