SlideShare a Scribd company logo
Dive into SObjectizer-5.5
SObjectizer Team, Jan 2016
Sixth Part: Synchronous Interaction
(at v.5.5.15)
This is the next part of the series of presentations with deep
introduction into features of SObjectizer-5.5.
This part is dedicated to synchronous interactions between
agents.
SObjectizer Team, Jan 2016
Introduction
SObjectizer Team, Jan 2016
A classical way of interaction between agents is
asynchronous messages.
Asynchronous interaction is simple, flexible and scalable. It
also could prevent some errors like deadlocks (but could
also lead to other kind of errors).
However, sometimes asynchronous interaction makes code
more complex and requires a lot of programmers work...
SObjectizer Team, Jan 2016
For example: sometimes an agent C must send a request to
an agent S and receive back a response with some
important information. The agent C can continue its work
only after arrival of information from agent S.
How we can express that scenario via asynchronous
messages?
SObjectizer Team, Jan 2016
We need a request message which must contain a mbox for
the response (since v.5.5.9 any struct/class which is
MoveConstructible can be used as a message):
struct get_config {
so_5::mbox_t reply_to;
};
We need a response which will be sent back:
struct config {
... // Some fields.
config(...); // Some constructor...
};
SObjectizer Team, Jan 2016
A skeleton for agent S is quite simple:
class config_manager : public so_5::agent_t {
...
public :
virtual void so_define_agent() override {
so_subscribe_self().event( &config_manager::evt_get_config );
... // Other subscriptions...
}
private :
void evt_get_config( const get_config & request ) {
// Sending a reply back.
so_5::send< config >( request.reply_to, ... /* some args */ );
}
};
SObjectizer Team, Jan 2016
But a skeleton of agent C is more complex:
class client : public so_5::agent_t {
// A special state to wait a response.
const so_5::state_t st_wait_config{ this, "wait_config" };
public :
virtual void so_define_agent() override {
// Agent should start its work in a special state.
this >>= st_wait_config;
// Reply with config data will be handled in that state.
st_wait_config.event( &client::evt_config );
...
}
virtual void so_evt_start() override {
// Request a config at start.
so_5::send< get_config >( config_manager_mbox, so_direct_mbox() );
}
private :
void evt_config( const config & cfg ) { ... /* Handling of configuration. */ }
};
SObjectizer Team, Jan 2016
It is a lot of code for such simple operation.
But this code is not robust enough.
For example, there will be no handling of the cases when
get_config request or config response are lost somewhere...
SObjectizer Team, Jan 2016
Synchronous interaction can help here.
An agent C can issue a service request to agent S and
receive the result of that request synchronously.
SObjectizer Team, Jan 2016
Let’s rewrite our small example with service request instead
of asynchronous messages...
SObjectizer Team, Jan 2016
A slight modification for request type. There is no need to
pass reply_to mbox in a request now. So, get_config
becomes a signal:
struct get_config : public so_5::signal_t {};
Response will remain the same:
struct config {
... // Some fields.
config(...); // Some constructors...
};
SObjectizer Team, Jan 2016
Service request processor will return config as a result of
event handler:
class config_manager : public so_5::agent_t {
...
public :
virtual void so_define_agent() override {
so_subscribe_self().event< get_config >( &config_manager::evt_get_config );
... // Other subscriptions...
}
private :
config evt_get_config() {
// Returning a reply back.
return config{ ... /* some args */ };
}
};
SObjectizer Team, Jan 2016
Service request issuer will look like:
class client : public so_5::agent_t {
public :
virtual void so_define_agent() override {
... // No special state, no subscription for config response.
}
virtual void so_evt_start() override {
// Request a config at start.
// Wait response for 1 second.
auto cfg = so_5::request_value< config, get_config >(
config_manager_mbox, std::chrono::seconds(1) );
}
...
};
SObjectizer Team, Jan 2016
That code is not only much simpler ‒ it is also more robust:
● if there is no service request processor behind
config_manager_mbox there will be an exception;
● if there are more than one service request processor behind
config_manager_mbox there will be an exception;
● if config_manager won’t process a request (request is ignored in the
current state of manager) there will be an exception;
● if config_manager can’t process a request, e.g. throw an exception,
that exception will be propagated to service request's issuer;
● if config_manager can’t process a request in the specified time slice
there will be an exception.
SObjectizer Team, Jan 2016
It means that in several cases synchronous interaction via
service requests is more appropriate than asynchronous
interaction.
In such cases service requests allow to write more simple,
clean and robust code…
...but everything has its price.
SObjectizer Team, Jan 2016
The main disadvantage of service request is a possibility of
deadlocks.
Service request’s issuer and processor must work on
different working threads.
It means that issuer and processor must be bound to
different dispatchers. Or, to the different working threads
inside the same dispatcher.
SObjectizer Team, Jan 2016
If an issuer and a processor work on the same working
thread there will be a deadlock.
SObjectizer doesn’t check that. A user is responsible for
binding issuer and processor to the different contexts.
SObjectizer Team, Jan 2016
But the case when an issuer and a processor are working on
the same thread is the simplest case of deadlock.
There could be more complex cases:
● agent A calls agent B;
● agent B calls agent C;
● agent C calls agent D;
● agent D calls agent A.
It is another kind of classical deadlock with the same
consequences.
SObjectizer Team, Jan 2016
Another disadvantage of service request is a blocking of a
working thread for some time.
If a service request issuer shares the working thread with
different agents (for example, all of them are bound to
one_thread dispatcher instance) then all other agents on that
thread will wait until the service request is completed.
It means that synchronous agents interaction is not very
scalable.
SObjectizer Team, Jan 2016
As shown above, the synchronous agents interaction has
significant disadvantages. Based on that, it should be used
with care.
SObjectizer Team, Jan 2016
How Does It Work?
SObjectizer Team, Jan 2016
There is no any magic behind service requests.
Just an ordinary asynchronous messages and some help
from std::promise and std::future...
SObjectizer Team, Jan 2016
When a service request is initiated a special envelope with
service requests params inside is sent as an ordinary
message to service request processor.
This envelope contains not only request params but also a
std::promise object for the response. A value for that
promise is set on processor’s side.
A service request issuer waits on std::future object which is
bound with std::promise from the envelope which was sent.
SObjectizer Team, Jan 2016
It means that so_5::request_value call in form:
auto r = so_5::request_value<Result,Request>(mbox, timeout, params);
It is a shorthand for something like that:
// Envelope will contain Request object and std::promise<Result> object.
auto env__ = std::make_unique<msg_service_request_t<Result,Request>>(params);
// Get the future to wait on it.
std::future<Result> f__ = env__.m_promise.get_future();
// Sending the envelope with request params as async message.
mbox->deliver_message(std::move(env__));
// Waiting and handling the result.
auto wait_result__ = f__.wait_for(timeout);
if(std::future_status::ready != wait_result__)
throw exception_t(...);
auto r = f__.get();
SObjectizer Team, Jan 2016
Every service request handler in the following form
Result event_handler(const Request & svc_req ) { ... }
is automatically transformed to something like this:
void actual_event_handler(msg_service_request_t<Result,Request> & m) {
try {
m.m_promise.set( event_handler(m.query_param()) );
}
catch(...) {
m.set_exception(std::current_exception());
}
}
This transformation is performed during subscription of
event_handler.
SObjectizer Team, Jan 2016
This approach of supporting synchronous interaction means
that service request is handled by SObjectizer just like
dispatching and handling of ordinary message.
As a consequence, a service request handler even doesn’t
know is a message it handles is a part of a service request
or it was sent as a asynchronous message?
Only the service request issuer knows the difference.
SObjectizer Team, Jan 2016
It means that a config_manager from the example above will
work in the same way even if get_config signal is sent via
so_5::send() function like any other async message.
But in this case the return value of config_manager::
evt_get_config will be discarded.
It means that there is no special rules for writing service
request handlers: they are just agents with traditional event
handlers. Except one important aspect...
SObjectizer Team, Jan 2016
This important aspect is exception handling.
If an agent allows an exception to go out from an event
handler then traditional reaction to unhandled exception will
be initiated:
● SObjectizer Environment will call so_exception_reaction() for that
agent (and may be for coop of that agent and so on);
● appropriate action will be taken (for example, an exception could
be ignored or the whole application will be aborted).
SObjectizer Team, Jan 2016
But if an exception is going out from service request handler
then it will be intercepted and returned back to service
request issuer via std::promise/std::future pair.
It means that this exception will be reraised on service
request issuer side during the call to std::future::get()
method. E.g. that exception will be thrown out from
request_value().
SObjectizer Team, Jan 2016
request_value and request_future functions
SObjectizer Team, Jan 2016
There are several ways of initiating service requests.
The simplest one is the usage of so_5::request_value()
template function. It can be used in the form:
Result r = so_5::request_value<Result, Request>(Target, Timeout [,Args]);
Where Timeout is a value which is defined by std::chrono or
so_5::infinite_wait for non-limited waiting of the result.
Type of Request can be any message or signal type. All
Args (if any) will be passed to the constructor of Request.
SObjectizer Team, Jan 2016
Examples of request_value invocations:
// Sending a get_status signal as service request.
auto v = so_5::request_value<engine_status, get_status>(engine,
// Infinite waiting for the response.
so_5::infinite_wait); // No other params because of signal.
// Sending a message convert_value as a service request.
auto v = so_5::request_value<std::string, convert_value>(converter,
// Waiting for 200ms for the response.
std::chrono::milliseconds(200),
"feets", 33000, "metres" ); // Params for the constructor of convert_value.
SObjectizer Team, Jan 2016
There is also so_5::request_future() template function. It
returns std::future<Result> object:
std::future<Result> r = so_5::request_future<Result, Request>(Target [,Args]);
There is no Timeout argument. Waiting on the std::future is
responsibility of a programmer.
As in the case of request_value type of Request can be any
of message or signal type. All Args (if any) will be passed to
the constructor of Request.
SObjectizer Team, Jan 2016
request_future can be used in more complex scenarios than
request_value. For example, it is possible to issue several
service requests, do some actions and only then request
responses:
auto lights = so_5::request_future<light_status, turn_light_on>(light_controller);
auto heating = so_5::request_future<heating_status, turn_heating_on>(heating_controller);
auto accessories = so_5::request_future<accessories_status, update>(accessories_controller);
... // Some other actions.
if(light_status::on != lights.get())
... // Some reaction...
if(heating_status::on != heating.get())
... // Some reaction...
check_accessories(accessories.get());
...
SObjectizer Team, Jan 2016
There could be more complex scenarios:
class accessories_listener : public so_5::agent_t {
public :
...
virtual void so_evt_start() override {
m_status = so_5::request_future< accessories_status, get_status >(accessories_controller());
// Service request initiated, but the response will be used later.
so_5::send_delayed< check_status >(*this, std::chrono::milliseconds(250));
}
private :
std::future<accessories_status> m_status;
...
void evt_check_status() {
auto status = m_status.get(); // Getting the service request response.
... // Processing it.
// Initiate new request again.
m_status = so_5::request_future< accessories_status, get_status >(accessories_controller());
// Response is expected to be ready on the next timer event
so_5::send_delayed< check_status >(*this, std::chrono::milliseconds(250));
}
};
SObjectizer Team, Jan 2016
Service Requests With void As Result Type
SObjectizer Team, Jan 2016
Sometimes there is some sense in initiating a service
request which returns void.
A result of such service request means that processing of a
request is completely finished. Sometimes, is it a very useful
information.
For example, if service request processor does flushing of
some important data, finishing transactions, invalidating
caches and so on...
SObjectizer Team, Jan 2016
An example of service request with void result:
// Type of agent which implements an intermediate buffer with flushing by demand or by timer.
class data_buffer : public so_5::agent_t {
public :
// Signal for flushing the data.
struct flush : public so_5::signal_t {};
...
private :
// Event which is bound to flush signal.
void evt_flush() {
... // Storing the data to the disk/database/cloud...
}
};
// Initiating flush operation as a service request. Return from request_value
// means the completeness of data flushing.
so_5::request_value<void, data_buffer::flush>(buffer, so_5::infinite_wait);
SObjectizer Team, Jan 2016
Additional Information:
Project’s home: http://sourceforge.net/projects/sobjectizer
Documentation: http://sourceforge.net/p/sobjectizer/wiki/
Forum: http://sourceforge.net/p/sobjectizer/discussion/
Google-group: https://groups.google.com/forum/#!forum/sobjectizer
GitHub mirror: https://github.com/masterspline/SObjectizer

More Related Content

PDF
Dive into SObjectizer 5.5. Third part. Coops
PDF
Dive into SObjectizer 5.5. Seventh part: Message Limits
PDF
Dive into SObjectizer 5.5. Fifth part: Timers
PDF
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
PDF
Dive into SObjectizer 5.5. Tenth part: Mutable Messages
PDF
Dive into SObjectizer 5.5. Fourth part. Exception
PDF
Dive into SObjectizer 5.5. Introductory part
PDF
Dive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Third part. Coops
Dive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Fifth part: Timers
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
Dive into SObjectizer 5.5. Tenth part: Mutable Messages
Dive into SObjectizer 5.5. Fourth part. Exception
Dive into SObjectizer 5.5. Introductory part
Dive into SObjectizer 5.5. Ninth Part: Message Chains

What's hot (20)

PDF
What is SObjectizer 5.5
PDF
arataga. SObjectizer and RESTinio in action: a real-world example
PDF
Date Processing Attracts Bugs or 77 Defects in Qt 6
PPTX
Android session-5-sajib
ODP
Testing RESTful Webservices using the REST-assured framework
ODP
Creating a Java EE 7 Websocket Chat Application
PDF
The Little Unicorn That Could
ODP
MQTT and Java - Client and Broker Examples
PDF
PVS-Studio vs Chromium. 3-rd Check
PPTX
Chain of Responsibility Pattern
PDF
Bot builder v4 HOL
PPTX
PDF
Miranda NG Project to Get the "Wild Pointers" Award (Part 1)
PDF
Checking Clang 11 with PVS-Studio
PDF
Static Analysis of Mozilla Thunderbird's Code by PVS-Studio
PDF
Mvc interview questions – deep dive jinal desai
PDF
PDF
Analyzing ReactOS One More Time
PDF
How to build to do app using vue composition api and vuex 4 with typescript
PDF
Understanding Asynchronous JavaScript
What is SObjectizer 5.5
arataga. SObjectizer and RESTinio in action: a real-world example
Date Processing Attracts Bugs or 77 Defects in Qt 6
Android session-5-sajib
Testing RESTful Webservices using the REST-assured framework
Creating a Java EE 7 Websocket Chat Application
The Little Unicorn That Could
MQTT and Java - Client and Broker Examples
PVS-Studio vs Chromium. 3-rd Check
Chain of Responsibility Pattern
Bot builder v4 HOL
Miranda NG Project to Get the "Wild Pointers" Award (Part 1)
Checking Clang 11 with PVS-Studio
Static Analysis of Mozilla Thunderbird's Code by PVS-Studio
Mvc interview questions – deep dive jinal desai
Analyzing ReactOS One More Time
How to build to do app using vue composition api and vuex 4 with typescript
Understanding Asynchronous JavaScript
Ad

Similar to Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction (13)

PDF
What is SObjectizer 5.7 (at v.5.7.0)
PDF
What’s new in SObjectizer 5.5.8
PDF
What is SObjectizer 5.6 (at v.5.6.0)
PDF
Rigadevdays - Communication in a microservice architecture
PPTX
Magento Developer Talk. Microservice Architecture and Actor Model
PPTX
Introduction to netlink in linux kernel (english)
PDF
Building Web APIs that Scale
PDF
Дмитрий Копляров , Потокобезопасные сигналы в C++
PDF
Specification and Verification of Contract-based Applications
PDF
What's new in SObjectizer 5.5.9
PDF
Microservices: What's Missing - O'Reilly Software Architecture New York
PPTX
Essential API Facade Patterns: Synchronous to Asynchronous Conversion (Episod...
PPTX
UNIT II DIS.pptx
What is SObjectizer 5.7 (at v.5.7.0)
What’s new in SObjectizer 5.5.8
What is SObjectizer 5.6 (at v.5.6.0)
Rigadevdays - Communication in a microservice architecture
Magento Developer Talk. Microservice Architecture and Actor Model
Introduction to netlink in linux kernel (english)
Building Web APIs that Scale
Дмитрий Копляров , Потокобезопасные сигналы в C++
Specification and Verification of Contract-based Applications
What's new in SObjectizer 5.5.9
Microservices: What's Missing - O'Reilly Software Architecture New York
Essential API Facade Patterns: Synchronous to Asynchronous Conversion (Episod...
UNIT II DIS.pptx
Ad

More from Yauheni Akhotnikau (13)

PDF
Actor Model and C++: what, why and how? (March 2020 Edition)
PDF
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
PDF
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
PDF
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
PDF
Акторы на C++: стоило ли оно того?
PDF
25 Years of C++ History Flashed in Front of My Eyes
PDF
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
PDF
Actor Model and C++: what, why and how?
PDF
Шишки, набитые за 15 лет использования акторов в C++
PDF
Для чего мы делали свой акторный фреймворк и что из этого вышло?
PDF
Модель акторов и C++ что, зачем и как?
PDF
Погружение в SObjectizer 5.5. Вводная часть
PDF
Обзор SObjectizer 5.5
Actor Model and C++: what, why and how? (March 2020 Edition)
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы на C++: стоило ли оно того?
25 Years of C++ History Flashed in Front of My Eyes
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
Actor Model and C++: what, why and how?
Шишки, набитые за 15 лет использования акторов в C++
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Модель акторов и C++ что, зачем и как?
Погружение в SObjectizer 5.5. Вводная часть
Обзор SObjectizer 5.5

Recently uploaded (20)

PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Introduction to Artificial Intelligence
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
medical staffing services at VALiNTRY
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
System and Network Administration Chapter 2
PPTX
Computer Software and OS of computer science of grade 11.pptx
PPTX
assetexplorer- product-overview - presentation
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Reimagine Home Health with the Power of Agentic AI​
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Operating system designcfffgfgggggggvggggggggg
2025 Textile ERP Trends: SAP, Odoo & Oracle
Softaken Excel to vCard Converter Software.pdf
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Introduction to Artificial Intelligence
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Design an Analysis of Algorithms I-SECS-1021-03
Digital Systems & Binary Numbers (comprehensive )
medical staffing services at VALiNTRY
PTS Company Brochure 2025 (1).pdf.......
VVF-Customer-Presentation2025-Ver1.9.pptx
System and Network Administration Chapter 2
Computer Software and OS of computer science of grade 11.pptx
assetexplorer- product-overview - presentation
wealthsignaloriginal-com-DS-text-... (1).pdf
Reimagine Home Health with the Power of Agentic AI​

Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction

  • 1. Dive into SObjectizer-5.5 SObjectizer Team, Jan 2016 Sixth Part: Synchronous Interaction (at v.5.5.15)
  • 2. This is the next part of the series of presentations with deep introduction into features of SObjectizer-5.5. This part is dedicated to synchronous interactions between agents. SObjectizer Team, Jan 2016
  • 4. A classical way of interaction between agents is asynchronous messages. Asynchronous interaction is simple, flexible and scalable. It also could prevent some errors like deadlocks (but could also lead to other kind of errors). However, sometimes asynchronous interaction makes code more complex and requires a lot of programmers work... SObjectizer Team, Jan 2016
  • 5. For example: sometimes an agent C must send a request to an agent S and receive back a response with some important information. The agent C can continue its work only after arrival of information from agent S. How we can express that scenario via asynchronous messages? SObjectizer Team, Jan 2016
  • 6. We need a request message which must contain a mbox for the response (since v.5.5.9 any struct/class which is MoveConstructible can be used as a message): struct get_config { so_5::mbox_t reply_to; }; We need a response which will be sent back: struct config { ... // Some fields. config(...); // Some constructor... }; SObjectizer Team, Jan 2016
  • 7. A skeleton for agent S is quite simple: class config_manager : public so_5::agent_t { ... public : virtual void so_define_agent() override { so_subscribe_self().event( &config_manager::evt_get_config ); ... // Other subscriptions... } private : void evt_get_config( const get_config & request ) { // Sending a reply back. so_5::send< config >( request.reply_to, ... /* some args */ ); } }; SObjectizer Team, Jan 2016
  • 8. But a skeleton of agent C is more complex: class client : public so_5::agent_t { // A special state to wait a response. const so_5::state_t st_wait_config{ this, "wait_config" }; public : virtual void so_define_agent() override { // Agent should start its work in a special state. this >>= st_wait_config; // Reply with config data will be handled in that state. st_wait_config.event( &client::evt_config ); ... } virtual void so_evt_start() override { // Request a config at start. so_5::send< get_config >( config_manager_mbox, so_direct_mbox() ); } private : void evt_config( const config & cfg ) { ... /* Handling of configuration. */ } }; SObjectizer Team, Jan 2016
  • 9. It is a lot of code for such simple operation. But this code is not robust enough. For example, there will be no handling of the cases when get_config request or config response are lost somewhere... SObjectizer Team, Jan 2016
  • 10. Synchronous interaction can help here. An agent C can issue a service request to agent S and receive the result of that request synchronously. SObjectizer Team, Jan 2016
  • 11. Let’s rewrite our small example with service request instead of asynchronous messages... SObjectizer Team, Jan 2016
  • 12. A slight modification for request type. There is no need to pass reply_to mbox in a request now. So, get_config becomes a signal: struct get_config : public so_5::signal_t {}; Response will remain the same: struct config { ... // Some fields. config(...); // Some constructors... }; SObjectizer Team, Jan 2016
  • 13. Service request processor will return config as a result of event handler: class config_manager : public so_5::agent_t { ... public : virtual void so_define_agent() override { so_subscribe_self().event< get_config >( &config_manager::evt_get_config ); ... // Other subscriptions... } private : config evt_get_config() { // Returning a reply back. return config{ ... /* some args */ }; } }; SObjectizer Team, Jan 2016
  • 14. Service request issuer will look like: class client : public so_5::agent_t { public : virtual void so_define_agent() override { ... // No special state, no subscription for config response. } virtual void so_evt_start() override { // Request a config at start. // Wait response for 1 second. auto cfg = so_5::request_value< config, get_config >( config_manager_mbox, std::chrono::seconds(1) ); } ... }; SObjectizer Team, Jan 2016
  • 15. That code is not only much simpler ‒ it is also more robust: ● if there is no service request processor behind config_manager_mbox there will be an exception; ● if there are more than one service request processor behind config_manager_mbox there will be an exception; ● if config_manager won’t process a request (request is ignored in the current state of manager) there will be an exception; ● if config_manager can’t process a request, e.g. throw an exception, that exception will be propagated to service request's issuer; ● if config_manager can’t process a request in the specified time slice there will be an exception. SObjectizer Team, Jan 2016
  • 16. It means that in several cases synchronous interaction via service requests is more appropriate than asynchronous interaction. In such cases service requests allow to write more simple, clean and robust code… ...but everything has its price. SObjectizer Team, Jan 2016
  • 17. The main disadvantage of service request is a possibility of deadlocks. Service request’s issuer and processor must work on different working threads. It means that issuer and processor must be bound to different dispatchers. Or, to the different working threads inside the same dispatcher. SObjectizer Team, Jan 2016
  • 18. If an issuer and a processor work on the same working thread there will be a deadlock. SObjectizer doesn’t check that. A user is responsible for binding issuer and processor to the different contexts. SObjectizer Team, Jan 2016
  • 19. But the case when an issuer and a processor are working on the same thread is the simplest case of deadlock. There could be more complex cases: ● agent A calls agent B; ● agent B calls agent C; ● agent C calls agent D; ● agent D calls agent A. It is another kind of classical deadlock with the same consequences. SObjectizer Team, Jan 2016
  • 20. Another disadvantage of service request is a blocking of a working thread for some time. If a service request issuer shares the working thread with different agents (for example, all of them are bound to one_thread dispatcher instance) then all other agents on that thread will wait until the service request is completed. It means that synchronous agents interaction is not very scalable. SObjectizer Team, Jan 2016
  • 21. As shown above, the synchronous agents interaction has significant disadvantages. Based on that, it should be used with care. SObjectizer Team, Jan 2016
  • 22. How Does It Work? SObjectizer Team, Jan 2016
  • 23. There is no any magic behind service requests. Just an ordinary asynchronous messages and some help from std::promise and std::future... SObjectizer Team, Jan 2016
  • 24. When a service request is initiated a special envelope with service requests params inside is sent as an ordinary message to service request processor. This envelope contains not only request params but also a std::promise object for the response. A value for that promise is set on processor’s side. A service request issuer waits on std::future object which is bound with std::promise from the envelope which was sent. SObjectizer Team, Jan 2016
  • 25. It means that so_5::request_value call in form: auto r = so_5::request_value<Result,Request>(mbox, timeout, params); It is a shorthand for something like that: // Envelope will contain Request object and std::promise<Result> object. auto env__ = std::make_unique<msg_service_request_t<Result,Request>>(params); // Get the future to wait on it. std::future<Result> f__ = env__.m_promise.get_future(); // Sending the envelope with request params as async message. mbox->deliver_message(std::move(env__)); // Waiting and handling the result. auto wait_result__ = f__.wait_for(timeout); if(std::future_status::ready != wait_result__) throw exception_t(...); auto r = f__.get(); SObjectizer Team, Jan 2016
  • 26. Every service request handler in the following form Result event_handler(const Request & svc_req ) { ... } is automatically transformed to something like this: void actual_event_handler(msg_service_request_t<Result,Request> & m) { try { m.m_promise.set( event_handler(m.query_param()) ); } catch(...) { m.set_exception(std::current_exception()); } } This transformation is performed during subscription of event_handler. SObjectizer Team, Jan 2016
  • 27. This approach of supporting synchronous interaction means that service request is handled by SObjectizer just like dispatching and handling of ordinary message. As a consequence, a service request handler even doesn’t know is a message it handles is a part of a service request or it was sent as a asynchronous message? Only the service request issuer knows the difference. SObjectizer Team, Jan 2016
  • 28. It means that a config_manager from the example above will work in the same way even if get_config signal is sent via so_5::send() function like any other async message. But in this case the return value of config_manager:: evt_get_config will be discarded. It means that there is no special rules for writing service request handlers: they are just agents with traditional event handlers. Except one important aspect... SObjectizer Team, Jan 2016
  • 29. This important aspect is exception handling. If an agent allows an exception to go out from an event handler then traditional reaction to unhandled exception will be initiated: ● SObjectizer Environment will call so_exception_reaction() for that agent (and may be for coop of that agent and so on); ● appropriate action will be taken (for example, an exception could be ignored or the whole application will be aborted). SObjectizer Team, Jan 2016
  • 30. But if an exception is going out from service request handler then it will be intercepted and returned back to service request issuer via std::promise/std::future pair. It means that this exception will be reraised on service request issuer side during the call to std::future::get() method. E.g. that exception will be thrown out from request_value(). SObjectizer Team, Jan 2016
  • 31. request_value and request_future functions SObjectizer Team, Jan 2016
  • 32. There are several ways of initiating service requests. The simplest one is the usage of so_5::request_value() template function. It can be used in the form: Result r = so_5::request_value<Result, Request>(Target, Timeout [,Args]); Where Timeout is a value which is defined by std::chrono or so_5::infinite_wait for non-limited waiting of the result. Type of Request can be any message or signal type. All Args (if any) will be passed to the constructor of Request. SObjectizer Team, Jan 2016
  • 33. Examples of request_value invocations: // Sending a get_status signal as service request. auto v = so_5::request_value<engine_status, get_status>(engine, // Infinite waiting for the response. so_5::infinite_wait); // No other params because of signal. // Sending a message convert_value as a service request. auto v = so_5::request_value<std::string, convert_value>(converter, // Waiting for 200ms for the response. std::chrono::milliseconds(200), "feets", 33000, "metres" ); // Params for the constructor of convert_value. SObjectizer Team, Jan 2016
  • 34. There is also so_5::request_future() template function. It returns std::future<Result> object: std::future<Result> r = so_5::request_future<Result, Request>(Target [,Args]); There is no Timeout argument. Waiting on the std::future is responsibility of a programmer. As in the case of request_value type of Request can be any of message or signal type. All Args (if any) will be passed to the constructor of Request. SObjectizer Team, Jan 2016
  • 35. request_future can be used in more complex scenarios than request_value. For example, it is possible to issue several service requests, do some actions and only then request responses: auto lights = so_5::request_future<light_status, turn_light_on>(light_controller); auto heating = so_5::request_future<heating_status, turn_heating_on>(heating_controller); auto accessories = so_5::request_future<accessories_status, update>(accessories_controller); ... // Some other actions. if(light_status::on != lights.get()) ... // Some reaction... if(heating_status::on != heating.get()) ... // Some reaction... check_accessories(accessories.get()); ... SObjectizer Team, Jan 2016
  • 36. There could be more complex scenarios: class accessories_listener : public so_5::agent_t { public : ... virtual void so_evt_start() override { m_status = so_5::request_future< accessories_status, get_status >(accessories_controller()); // Service request initiated, but the response will be used later. so_5::send_delayed< check_status >(*this, std::chrono::milliseconds(250)); } private : std::future<accessories_status> m_status; ... void evt_check_status() { auto status = m_status.get(); // Getting the service request response. ... // Processing it. // Initiate new request again. m_status = so_5::request_future< accessories_status, get_status >(accessories_controller()); // Response is expected to be ready on the next timer event so_5::send_delayed< check_status >(*this, std::chrono::milliseconds(250)); } }; SObjectizer Team, Jan 2016
  • 37. Service Requests With void As Result Type SObjectizer Team, Jan 2016
  • 38. Sometimes there is some sense in initiating a service request which returns void. A result of such service request means that processing of a request is completely finished. Sometimes, is it a very useful information. For example, if service request processor does flushing of some important data, finishing transactions, invalidating caches and so on... SObjectizer Team, Jan 2016
  • 39. An example of service request with void result: // Type of agent which implements an intermediate buffer with flushing by demand or by timer. class data_buffer : public so_5::agent_t { public : // Signal for flushing the data. struct flush : public so_5::signal_t {}; ... private : // Event which is bound to flush signal. void evt_flush() { ... // Storing the data to the disk/database/cloud... } }; // Initiating flush operation as a service request. Return from request_value // means the completeness of data flushing. so_5::request_value<void, data_buffer::flush>(buffer, so_5::infinite_wait); SObjectizer Team, Jan 2016
  • 40. Additional Information: Project’s home: http://sourceforge.net/projects/sobjectizer Documentation: http://sourceforge.net/p/sobjectizer/wiki/ Forum: http://sourceforge.net/p/sobjectizer/discussion/ Google-group: https://groups.google.com/forum/#!forum/sobjectizer GitHub mirror: https://github.com/masterspline/SObjectizer