Skip to content
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

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

Open
eao197 opened this issue Oct 19, 2023 · 0 comments
Assignees

Comments

@eao197
Copy link
Member

eao197 commented Oct 19, 2023

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).

@eao197 eao197 self-assigned this Oct 19, 2023
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

No branches or pull requests

1 participant