Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Dive into SObjectizer 5.5. Third part. Coops

This is the next part of the serie of presentations with deep introduction into features of SObjectizer-5.5.

This part is dedicated to such important feature as cooperations.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to comment

Dive into SObjectizer 5.5. Third part. Coops

  1. 1. Dive into SObjectizer-5.5 SObjectizer Team, Jan 2016 Third Part: More About Coops (at v.5.5.15)
  2. 2. This is the next part of the serie of presentations with deep introduction into features of SObjectizer-5.5. This part is dedicated to such important feature as cooperations. In particular: ● parent-child relationship; ● resource lifetime management; ● reg/dereg notificators. SObjectizer Team, Jan 2016
  3. 3. Parent-Child Relationship SObjectizer Team, Jan 2016
  4. 4. Cooperation (or coop in short) is a way for binding several tightly related agents into a whole entity. Coop is registered in SObjectizer Environment in a transactional manner: all agents from the cooperation must be registered successfully or no one of them. When a coop is being deregistered all its agents are deregistered and destroyed at the same time. SObjectizer Team, Jan 2016
  5. 5. There could be agents which require creation of additional coop(s) for performing their work. Let's imagine an agent which is responsible of receiving and processing of some requests. Payment requests, for example. SObjectizer Team, Jan 2016
  6. 6. Processing of each payment request requires several operations: ● checking payments parameters, ● checking the operation risks, ● checking the availability of funds ● and so on... The request receiver could do those actions for every payment by itself. But this will lead to very complicated logic of request receiver. SObjectizer Team, Jan 2016
  7. 7. There is much simpler approach: delegation of processing of one request to a separate processor agent. In that case the request receiver will only receive new requests and create new coops with actual request processors for each new request. Receiver and processor agents will have more simple logic and it is good. But there will be a new question... SObjectizer Team, Jan 2016
  8. 8. Who and how will control lifetime of all cooperations with request processors? SObjectizer Team, Jan 2016
  9. 9. Very simple view of that problem: Someone could call deregister_coop() for request receiver’s coop. As result all coops with request processors must be deregistered too. But how it could be done? SObjectizer Team, Jan 2016
  10. 10. Such feature as child coop is coming into play here. SObjectizer Team, Jan 2016
  11. 11. SObjectizer-5 allows to mark new coop as a child of any existing coop. In this case SObjectizer guarantees that all children coops will be deregistered and destroyed before its parent coop. SObjectizer Team, Jan 2016
  12. 12. It means that if we have, for example, a parent coop with name “manager” and a child coop with name “request_receiver” and do call: env.deregister_coop( "manager", so_5::dereg_reason::normal ); Then SObjectizer-5 will deregister and destroy “request_receiver” and only then “manager” coop will be deregistered and destroyed. SObjectizer Team, Jan 2016
  13. 13. Child coop could have its own child coops too. It means that “request_receiver” coop could have any number of child coops like “request_processor_1”, “request_processor_2” and so on. All of them will be automatically destroyed when top-level parent coop “manager” is deregistered. SObjectizer Team, Jan 2016
  14. 14. Parent-child relationship between coops allows to build coops hierarchies: a top-level coop creates child coops, those create its own child coops and so on. If a top-level coop is being deregistered by some reason then all its child coops (and children of children and so on) will be deregistered too. A programmer could no takes care about this. SObjectizer Team, Jan 2016
  15. 15. There are several ways to make a child coop... SObjectizer Team, Jan 2016
  16. 16. The first way, the oldest and verbose: auto coop = env.create_coop( "request_processor_1" ); coop->set_parent_coop_name( "request_receiver" ); ... // Filling the coop. env.register_coop( std::move( coop ) ); Coop “request_processor_1” will be a child for coop “request_receiver”. SObjectizer Team, Jan 2016
  17. 17. The second one applicable if there is an agent from the parent coop: void parent_agent::make_new_coop() { auto coop = so_5::create_child_coop( *this, "request_processor_1" ); ... // Filling the coop. so_environment().register_coop( std::move( coop ) ); } Name of the parent coop will be set automatically. SObjectizer Team, Jan 2016
  18. 18. The third one is available since v.5.5.5: void parent_agent::make_new_coop() { so_5::introduce_child_coop( *this, "request_processor_1", []( so_5::coop_t & coop ) { ... // Filling the coop. } ); } Name of the parent coop will be set automatically. SObjectizer Team, Jan 2016
  19. 19. Resource Lifetime Management SObjectizer Team, Jan 2016
  20. 20. Sometimes it is necessary to manage lifetime of some resources. For example all agents from your coop should have a reference to the same DB connection object. If this connection object is allocated dynamically you can pass a shared_ptr to every agent's constructor. Something like: SObjectizer Team, Jan 2016
  21. 21. class first_agent : public so_5::agent_t { ... public : first_agent( context_t ctx, std::shared_ptr< db_connection > conn, ... ); ... private : std::shared_ptr< db_connection > connection_; }; class second_agent : public so_5::agent_t { ... public : second_agent( context_t ctx, std::shared_ptr< db_connection > conn, ... ); ... private : std::shared_ptr< db_connection > connection_; }; env.introduce_coop( []( so_5::coop_t & coop ) { std::shared_ptr< db_connection > connection = connect_to_db(...); coop.make_agent< first_agent >( connection, ... ); coop.make_agent< second_agent >( connection, ... ); ... } ); SObjectizer Team, Jan 2016
  22. 22. In such case you make tight coupling between application domain logic of your agents and DB connection lifetime management. SObjectizer Team, Jan 2016
  23. 23. What if this lifetime management need to be changed in the future? What if connection object is controlled by someone else and you have a simple reference to it (not shared_ptr)? You will need to do some rewriting... SObjectizer Team, Jan 2016
  24. 24. class first_agent : public so_5::agent_t { ... public : first_agent( context_t ctx, db_connection & conn, ... ); // The constructor has to be changed. ... private : db_connection & connection_; // Declaration of the member has to be changed. }; class second_agent : public so_5::agent_t { ... public : second_agent( context_t ctx, db_connection & conn, ... ); // The constructor has to be changed. ... private : db_connection & connection_; // Declaration of the member has to be changed. }; ... db_connection & conn = receive_connection_from_somewhere(); env.introduce_coop( [&conn]( so_5::coop_t & coop ) { coop.make_agent< first_agent >( conn, ... ); coop.make_agent< second_agent >( conn, ... ); ... } ); SObjectizer Team, Jan 2016
  25. 25. SObjectizer-5 has a tool for decoupling resource lifetime management from agent's domain-specific logic. This is coop_t::take_under_control(). Method coop_t::take_under_control() allows to pass dynamically allocated object under the control of the cooperation. The object placed under control will be deallocated only after destroying all agents of the coop. SObjectizer Team, Jan 2016
  26. 26. The behaviour of take_under_control() allows to use the reference to controlled object even from agent's destructor... SObjectizer Team, Jan 2016
  27. 27. class request_processor : public so_5::agent_t { public : request_processor( context_t ctx, db_connection & connection ); ~request_processor() { if( !commited() ) // Assume that this reference is still valid. connection_.commit(); } ... private : db_connection & connection_; }; ... env.introduce_coop( []( so_5::coop_t & coop ) { // Place DB connection under the control of the cooperation. auto & connection = *coop.take_under_control(create_connection(...)); // Reference to DB connection will be valid even in requests_processor's destructor. coop->make_agent< request_processor >( connection ); ... } ); SObjectizer Team, Jan 2016
  28. 28. Parent-child relationship could also be used for resource lifetime management... SObjectizer Team, Jan 2016
  29. 29. class request_receiver : public so_5::agent_t { std::unique_ptr< db_connection > connection_; ... public : virtual void so_evt_start() override { connection_ = make_db_connection(...); ... } ... private : void evt_new_request( const request & evt ) { // New request handler must be created. so_5::introduce_child_coop( *this, [=]( so_5::coop_t & coop ) { // Reference to DB connection will be valid even in requests_processor's destructor. // It is because agents from child cooperation will be destroyed before any of // agents from the parent cooperation. coop->make_agent< request_processor >( connection ); ... } ); } }; SObjectizer Team, Jan 2016
  30. 30. Reg/Dereg Notificators SObjectizer Team, Jan 2016
  31. 31. It is not easy to detect precise moments when a coop is completely registered or completely deregistered. The biggest problem is a detection of complete coop deregistration. It is because calling to environment_t::deregister_coop() just initiates coop deregistration process. But the entire process of deregistration could take a long time. SObjectizer Team, Jan 2016
  32. 32. To simplify that there are such things as registration and deregistration notificators. Notificator could be bound to a coop and it will be called when coop registration/deregistration process is finished. SObjectizer Team, Jan 2016
  33. 33. The simplest reg/dereg notificators: env.introduce_coop( []( so_5::coop_t & coop ) { coop.add_reg_notificator( []( so_5::environment_t &, const std::string & name ) { std::cout << "registered: " << name << std::endl; } ); coop.add_dereg_notificator( []( so_5::environment_t &, const std::string & name, const so_5::coop_dereg_reason_t & ) { std::cout << "deregistered: " << name << std::endl; } ); ... } ); Name of coop will be printed to stdout on coop registration and deregistration. SObjectizer Team, Jan 2016
  34. 34. Usually reg/dereg notifications are used for sending messages to some mboxes. Because this scenario is widely used there are two ready-to- use notificators in SObjectizer-5.5. They are created by make_coop_reg_notificator() and make_coop_dereg_notificator() functions... SObjectizer Team, Jan 2016
  35. 35. The standard notificators: auto notify_mbox = env.create_local_mbox(); env.introduce_coop( [&]( so_5::coop_t & coop ) { // An instance of so_5::msg_coop_registered will be sent to notify_mbox // when the cooperation is registered. coop.add_reg_notificator( so_5::make_coop_reg_notificator( notify_mbox ) ); // An instance of so_5::msg_coop_deregistered will be sent to // notify_mbox when the cooperation is deregistered. coop.add_dereg_notificator( so_5::make_coop_dereg_notificator( notify_mbox ) ); ... } ); SObjectizer Team, Jan 2016
  36. 36. Coop dereg notificators can be used for implementation of Erlang-like supervisors. For example, request receiver could receive notification about deregistration of child coops and restart them if they fail... SObjectizer Team, Jan 2016
  37. 37. Very simple way of controlling a child (1/2): class request_receiver : public so_5::agent_t { public : virtual void so_define_agent() override { // msg_coop_deregistered must be handled. so_subscribe_self().event( &request_receiver::evt_child_finished ); ... } ... private : void evt_new_request( const request & req ) { auto child_name = store_request_info( req ); so_5::introduce_child_coop( child_name, [&]( so_5::coop_t & coop ) { ... // Filling the coop with agents. // Dereg notificator is necessary to receive info about child disappearance. SObjectizer Team, Jan 2016
  38. 38. Very simple way of controlling a child (2/2): // Standard notificator will be used. coop.add_dereg_notificator( // We want a message to request_receiver direct_mbox. so_5::make_coop_dereg_notificator( so_direct_mbox() ) ); } ); ... } void evt_child_finished( const so_5::msg_coop_deregistered & evt ) { // If child cooperation failed its dereg reason will differ // from the normal value. if( so_5::dereg_reason::normal != evt.m_reason.reason() ) recreate_child_coop( evt.m_coop_name ); else remove_request_info( evt.m_coop_name ); } ... }; SObjectizer Team, Jan 2016
  39. 39. That is almost all what it needs to be known about agent coops. There are yet more issues like coop deregistration reasons and exception reaction inheritance… But those topics will be covered in the next parts of “Dive into SObjectizer-5.5” SObjectizer Team, Jan 2016
  40. 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

    Be the first to comment

  • MarkusWimmer1

    Jun. 13, 2020

This is the next part of the serie of presentations with deep introduction into features of SObjectizer-5.5. This part is dedicated to such important feature as cooperations.

Views

Total views

571

On Slideshare

0

From embeds

0

Number of embeds

6

Actions

Downloads

26

Shares

0

Comments

0

Likes

1

×