Stiffstream / sobjectizer

An implementation of Actor, Publish-Subscribe, and CSP models in one rather small C++ framework. With performance, quality, and stability proved by years in the production.

Home Page:https://stiffstream.com/en/products/sobjectizer.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[idea] Make so5extra's revocable timers the default implementation for timers in SObjectizer

eao197 opened this issue · comments

Historically the standard SObjectizer's timers are not truly cancel-able (revocable): a user can call timer_id_t::release() method, but if a message is already in an event_queue then it will be delivered to the receiver anyway.

After addition of enveloped messages functionality there is a way to implement almost truly cancel-able messages that can be revocable messages. It is used in so5extra's revocable timers: a delayed/periodic message is wrapped into a special envelope with an atomic flag inside, when timer is cancelled this atomic flag is dropped and the payload of an envelope is hidden (not delivered to) from the receiver. It looks like canceling the message delivery.

So the idea is: replace the default SObjectizer's implementation of delayed/periodic messages with so5extra's revocable timers.

It should not be hard because so5extra's revocable timers were designed as a drop-in replacement for standard SObjectizer's timers.

But there are some tricky moments.


The standard so_5::send_delayed doesn't return timer_id, so delivering of the delayed message won't be canceled if a user writes code like that:

so_5::send_delayed<msg_check_status>(*this, 125ms);

But so_5::extra::revocable_timer::send_delayed returns the timer_id and if this value won't be stored then the delayed delivery will be canceled:

using namespace so_5::extra::revocable_timer;
std::ignore = send_delayed<msg_check_status>(*this, 125ms); // The message will be canceled automatically.

So I see a possible solution this way:

using namespace so_5::extra::revocable_timer;
// Have to call `detach` method on returned timer_id_t.
send_delayed<msg_check_status>(*this, 125ms).detach(); // Now message becomes non-revocable.

Or this way

using namespace so_5::extra::revocable_timer;
// Have to assign the returned timer_id_t to a special "variable".
detached = send_delayed<msg_check_status>(*this, 125ms);

The second way looks more attractive for me.


Even so5extra's revocable timers are not truly revocable if multi-consumer delivery happens :(

For example:

const so_5::mbox_t mpmc_mbox = env.create_mbox(); // Ordinary MPMC mbox.
... // Several agents make subscription for a message from mpmc_mbox.
auto id = so_5::extra::revocable_timer::send_delayed<msg_shutdown_the_computer>(mpmc_mbox, 500ms);
...
id.release(); // (1) Canceling the delayed delivery.

At the point (1) we can find ourselves in a case where msg_shutdown_the_computer is already pushed into receivers' event_queues. And some receivers have already received it. Canceling the delivery prevents the message from being processed by the remaining receivers, but several receivers have already processed the message and we can't revert it :(


Because implementation of such an idea may break compatibility it has to be postponed to version 5.9 (at least).