|
SObjectizer
5.8
|
A major change was introduced in v.5.3.0 – a possibility to synchronously wait for result of message processing. An agent, called service client, could ask another agent (called service_handler) to do something by asynchronously sending message to service_handler and then synchronously waiting for the result of that request.
All parameters for service request must be defined as an ordinary message or a signal type:
Service request handler is an ordinary agent which defines its service_request handling methods by traditional way. The only change with previous version is that event handlers could return values since v.5.3.0:
Event handler methods are subscribed as usual:
All of these mean that there is almost no differences for service_handler: it always works as an ordinary agent. And all event handlers for that agent are invoked on agent’s working thread.
All requests are delivered to service_handler’s agent as ordinary messages via agent’s event queue. The mechanism for event handler invocation for service requests is the same as for traditional asynchronous messages.
To send service request it is necessary to call so_5::request_value template function:
This call will send msg_get_status signal to the target processor and will wait for the result for timeout.
A mbox, a reference to an agent, an ad-hoc agent proxy could be used as target argument for so_5::request_value() function. A caller must ensure that there is only one receiver of msg_get_status behind that argument.
The timeout argument is very important.
The most simple and the most dangerous way, is to wait service request result infinitely long:
The second way, which is much more safer, is to wait service request result for the specified amount of time:
There is also template function so_5::request_future() which provides the most complex and the most flexible way for issuing service request. It returns std::future object associated with service request. A user then can perform any operation he wish:
When a service request is initiated a special envelope with service requests params inside is sent as 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 sent.
It means that so_5::request_value call in form:
is a shorthand for something like that:
Every service request handler in form
is automatically transformed to something like this:
This transformation is performed during subscription of event_handler.
There is no any help to user from SObjectizer to avoid or to diagnose deadlocks when synchronous interactions are used. It is the user task to guarantee that service_handler and service client are working on different threads and there is no any complex internal interactions like: agent A1 calls A2 which calls A3 which calls A1.
It is the reason why the usage of so_5::infinite_wait is dangerous. If there is a deadlock the application will hang forever.
The safest way – is to use so_5::request_value with the reasonable timeout. Even if a deadlock is here it will be automatically destroyed after timeout expiration.
There is a huge possibility of exception appearance during synchronous interactions.
Some exceptions could be raised by SObjectizer. Those are:
In such cases SObjectizer raises object of so_5::exception_t class with the appropriate error_code inside.
Some exceptions could be raised by event handlers itself. As in the sample of evt_convert event above. Those exceptions are intercepted by SObjectizer and then transferred to the std::future connected with the service request. It means that those exceptions will be reraised during std::future::get() invocation. So, the application exception which are went out from event handler will be propagated to the service client.
The dialing with non-handled application exception is the main difference between ordinary event-handling and service_request-handling. When agent lets the exception go out during ordinary event handler invocation then SObjectizer calls agent’s so_exception_reaction() method and does appropriate actions. But when agent lets the exception go out during service_request handling then the exception is propagated to service client and so_exception_reaction() is not called.