SObjectizer  5.5
so-5.3.0: Ad-hoc agents

Introduction

A new type of agents is introduced in v.5.3.0 – ad-hoc agents. They are agents which could be constructed and registered without necessity of defining dedicated C++ class.

To construct ad-hoc agent is necessary to call define_method for cooperation object. This method returns a special proxy object which is used to definition of behaviour of new agent. For example this method chain creates agents which handles a message and a signal.

auto coop = env.create_coop( "sample" );
// Definition of ad-hoc agent.
coop->define_agent()
// First event for that agent.
.event(
// A mbox as message source.
some_mbox,
// Event handling code. Type of message is deduced automatically.
[]( const msg_convert & msg ) -> int {
return std::atoi( msg.m_value );
} )
// Second event for that agent.
// A mbox as message source.
some_mbox,
// Type of signal. Must be specified explicitly.
so_5::signal< msg_get_status >,
// Event handling code.
[]() -> std::string {
return "ready";
} );

Details

Binding ad-hoc agent to the specified dispatcher

Ad-hoc agent uses default cooperation dispatcher binder:

auto coop = env.create_coop( "active", so_5::disp::active_obj::create_disp_binder( "1" ) );
// First active agent.
coop->define_agent().event( ... );
// Second active agent.
coop->define_agent().event( ... );

But another dispatcher binder could be specified as an argument for define_agent() method:

auto coop = env.create_coop( "active", so_5::disp::active_obj::create_disp_binder( "1" ) );
// This agent will be active because it uses cooperation binder object.
coop->define_agent().event( ... );
// This agent will be passive.
coop->define_agent( so_5::rt::create_default_disp_binder() ).event( ... );

Specifying starting and finish ad-hoc agent actions

Ordinary agents have so_evt_start() and so_evt_finish() methods which are called at the start and at the end of agent work. Similar behaviour could be specified to ad-hoc agents by on_start() and on_finish() methods chains:

auto coop = env.create_coop( "demo" );
coop->define_agent()
// A start action for the agent.
.on_start( []() {
std::cout << "Agent started" << std::endl;
} )
// A finish action for the agent.
.on_finish( []() {
std::cout << "Agent finished" << std::endl;
} )
...

Specifying exception reaction for ad-hoc agent

Ordinary agents could reimplement so_exception_reaction() method to specify reaction to non-handled exceptions. Ad-hoc agents do not have that method. If ad-hoc agent should specify some reaction to non-handled exception this could be done by exception_reaction() method chain:

coop->define_agent()
// Exception from that agent could be safely ignored.
.exception_reaction( so_5::rt::ignore_exception )
.event( target_mbox,
[target_mbox]( const msg_payment_request & msg ) {
if( "RUR" == msg.currency_code() )
{
std::unique_ptr< msg_payment_request > new_request( new msg_payment_request( msg ) );
new_request->set_currency_code( "RUB" );
target_mbox->deliver_message( std::move( new_request ) );
}
else
target_mbox->deliver_message( new msg_payment_request( msg ) );
} );

Major differences from ordinary agents

Ad-hoc agents have the following major differences from ordinary agents.

No access to SObjectizer Environment

Ad-hoc agents have no access to so_environment. An ordinary agent could do:

void a_some_agent_t::evt_shutdown_signal()
{
// SObjectizer RunTime should be shut down.
so_environment().stop();
}

Ad-hoc agent should store reverence to so_enviroment as a capture variable:

auto coop = so_environment().create_coop( "child" );
so_5::rt::so_environment_t & env = so_environment();
coop->define_agent()
.event( some_mbox, so_5::signal< msg_shutdown_signal >,
// Note that env is captured by reference!
[&env]() { env.stop(); } );

No states

Ad-hoc agents cannot have states. Ordinary agents could define states by creating so_5::rt::state_t objects and then switching from one state to another. Ad-hoc agents have only one state which is hidden from the developer.

No access to cooperation

Ad-hoc agents have no access to the cooperation they belong. The ordinary agent could do:

void a_some_agent_t::evt_some_event()
{
if( ...Work is impossible... )
so_environment().deregister_coop( so_coop_name() );
}

But ad-hoc agent cannot.

Inability to receive event_data_t as argument

Lambda functions which are used as event handlers for ad-hoc agents should have one of the following prototypes:

// For ordinary message handling.
Result (const Message & )
// For signal handling.
Result ()

It is impossible to pass event_data_t object as argument to ad-hoc agent's event. So it is impossible to resend the same message object from ad-hoc agent's event (because there is not access to so_5::rt::event_data_t::make_reference() method).