-
Notifications
You must be signed in to change notification settings - Fork 5
so5extra 1.3 Revocable Messages
A new feature has been introduced in SObjectizer v.5.5.23: enveloped messages. This feature allows implementing revocable messages: messages/signals that can be revoked during delivery.
Ordinary SObjectizer's messages/signals are not revocable. Once an user calls send()
:
so_5::send<my_message>(target, ...);
the delivery of my_message
instance can't be affected by the sender.
Sometimes a message sent should be revoked. For example, we can have session_handler
agent that handles interaction with a user. And we can have pdf_generator
agent that performs CPU-intensive operations of the generation of PDF-file from user-specific data. Agent session_handler
sends a generate_pdf
message to pdf_generator
and then expects a reply with generated PDF-file.
But session_handler
can detect that the user closed session. In that case, all previous generate_pdf
messages have to be revoked. There is no need to handle them and waste pdf_generator
resources. But we can't do that if we are using ordinary SObjectizer messages.
The new stuff from so_5::extra::revocable_msg
allows solving that problem. We can send generate_pdf
as an revocable message and we can revoke message sent when a user closes the session.
Revocation of message doesn't mean that message will be extracted from all event queues at the moment of revocation. It is simply impossible.
Revocable delivery is implemented via a special envelope. And that envelope will stay inside all event queues until it will be extracted for processing the usual way. But if the envelope is revoked it won't be handled.
If a revocable message is transformed during delivery (as part of limit_then_transform
overlimit reaction or because message was collected by collecting mbox) then transformed message can't be revoked. Transformed message regarded as a new one, that has no relation to original revocable message.
All stuff related to revocable messages are defined in so_5_extra/revocable_msg/pub.hpp
header file. So to use this functionality it is necessary to include that file and so_5/all.hpp
file:
#include <so_5_extra/revocable_msg/pub.hpp>
#include <so_5/all.hpp>
To send a revocable message or signal it is necessary to use a send
function from so_5::extra::revocable_msg
and to store the delivery_id_t
instance returned. For example:
class session_handler final : public so_5::agent_t {
...
// ID of revocable message.
so_5::extra::revocable_msg::delivery_id_t current_pdf_request_;
...
void on_generate_document_cmd(mhood_t<generate_doc_cmd> cmd) {
if(doc_type::pdf == cmd->doc_type()) {
// Send a request to pdf_generator.
current_pdf_request_ = so_5::extra::revocable_msg::send<generate_pdf>(...);
...
}
else ...
}
...
};
To revoke message/signal sent these ways can be used:
- Destruction of
delivery_id_t
object. Destructor ofdelivery_id_t
automatically revokes message/signal sent. - Calling
delivery_id_t::revoke()
method. This method revokes message/signal sent. It is safe to callrevoke()
several times. - Assigning a new value to
delivery_id_t
object. Previously sent message/signal is revoked in this case.
For example:
class session_handler final : public so_5::agent_t {
...
// ID of revocable message.
// Last sent generate_pdf message will be remoked automatically
// during destruction of session_handler.
so_5::extra::revocable_msg::delivery_id_t current_pdf_request_;
...
void on_generate_document_cmd(mhood_t<generate_doc_cmd> cmd) {
if(doc_type::pdf == cmd->doc_type()) {
// Send a request to pdf_generator.
// Previously sent message will be revoked automatically.
current_pdf_request_ = so_5::extra::revocable_msg::send<generate_pdf>(...);
...
}
else ...
}
...
void on_cancel_document_generation(mhood_t<cancel_generate_doc_cmd> cmd) {
// Last sent generate_pdf will be revoked.
current_pdf_request_.revoke();
...
}
};
There are several forms of send()
functions in so_5::extra::revocable_msg
namespace. They are mimic send()
functions from main so_5
namespace.
The first form constructs a new message instance and sends it to mbox, mchain or to a direct mbox of agent/ad-hoc agent:
auto id = so_5::extra::revocable_msg::send<my_message>(destination,
... /* Arguments for my_message's constructor */
);
The second form allows to resend an existing message/signal as a revocable one:
void on_some_event(mhood_t<some_msg> cmd) {
auto id = so_5::extra::revocable_msg::send(destination, std::move(cmd));
}
There is no send_delayed
nor send_periodic
functions in so_5::extra::revocable_msg
namespace. Revocable timers are implemented in so_5::extra::revocable_timer
namespace.
A message/signal that sent via so_5::extra::revocable_msg::send()
function is enveloped into a special envelope with atomic revocation flag inside. A smart pointer to that envelope is stored inside delivery_id_t
object. That smart pointer is released when the message is revoked.
The revocation means setting a special flag value inside the envelope. The envelope checks that flag in access_hook()
method and provides the access to enveloped message/signal only if that flag is not set.
Revocation of message/signal doesn't affect message limits. It means that send()
increments message counter, but revoke()
doesn't decrement it. Message counter will be decremented only on the extraction of an envelope with a message from an event queue.