012-actor-lifetime.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // Copyright (c) 2019-2023 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  3. //
  4. // Distributed under the MIT Software License
  5. //
  6. #include "rotor.hpp"
  7. #include "supervisor_test.h"
  8. #include "actor_test.h"
  9. #include "access.h"
  10. namespace r = rotor;
  11. namespace rt = r::test;
  12. static std::uint32_t destroyed = 0;
  13. struct sample_actor_t : public r::actor_base_t {
  14. std::uint32_t event_current = 1;
  15. std::uint32_t event_init_start = 0;
  16. std::uint32_t event_init_finish = 0;
  17. std::uint32_t event_start = 0;
  18. std::uint32_t event_shutdown_start = 0;
  19. std::uint32_t event_shutdown_finish = 0;
  20. r::state_t &get_state() noexcept { return state; }
  21. using r::actor_base_t::actor_base_t;
  22. ~sample_actor_t() override { ++destroyed; }
  23. void init_start() noexcept override {
  24. event_init_start = event_current++;
  25. r::actor_base_t::init_start();
  26. }
  27. void init_finish() noexcept override {
  28. event_init_finish = event_current++;
  29. r::actor_base_t::init_finish();
  30. }
  31. void on_start() noexcept override {
  32. event_start = event_current++;
  33. r::actor_base_t::on_start();
  34. }
  35. void shutdown_start() noexcept override {
  36. event_shutdown_start = event_current++;
  37. r::actor_base_t::shutdown_start();
  38. }
  39. void shutdown_finish() noexcept override {
  40. event_shutdown_finish = event_current++;
  41. r::actor_base_t::shutdown_finish();
  42. }
  43. };
  44. struct custom_child_manager_t : public r::plugin::child_manager_plugin_t {
  45. r::address_ptr_t fail_addr;
  46. r::extended_error_ptr_t fail_ec;
  47. void on_shutdown_fail(r::actor_base_t &actor_, const r::extended_error_ptr_t &ec) noexcept override {
  48. fail_addr = actor_.get_address();
  49. fail_ec = ec;
  50. }
  51. };
  52. struct custom_supervisor_t : rt::supervisor_test_t {
  53. using rt::supervisor_test_t::supervisor_test_t;
  54. using plugins_list_t =
  55. std::tuple<r::plugin::address_maker_plugin_t, r::plugin::locality_plugin_t,
  56. r::plugin::delivery_plugin_t<r::plugin::local_delivery_t>, r::plugin::lifetime_plugin_t,
  57. r::plugin::init_shutdown_plugin_t, r::plugin::foreigners_support_plugin_t, custom_child_manager_t,
  58. r::plugin::starter_plugin_t>;
  59. };
  60. struct fail_plugin_t : public r::plugin::plugin_base_t {
  61. static bool allow_init;
  62. bool allow_shutdown = true;
  63. static std::type_index class_id;
  64. const std::type_index &identity() const noexcept override { return class_id; }
  65. void activate(r::actor_base_t *actor_) noexcept override {
  66. reaction_on(reaction_t::INIT);
  67. reaction_on(reaction_t::SHUTDOWN);
  68. return r::plugin::plugin_base_t::activate(actor_);
  69. }
  70. bool handle_init(r::message::init_request_t *) noexcept override { return allow_init; }
  71. bool handle_shutdown(r::message::shutdown_request_t *) noexcept override { return allow_shutdown; }
  72. };
  73. std::type_index fail_plugin_t::class_id = typeid(fail_plugin_t);
  74. TEST_CASE("actor lifetimes", "[actor]") {
  75. r::system_context_t system_context;
  76. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  77. auto act = sup->create_actor<sample_actor_t>().timeout(rt::default_timeout).finish();
  78. REQUIRE(act->get_state() == r::state_t::INITIALIZING);
  79. sup->do_process();
  80. REQUIRE(act->get_state() == r::state_t::OPERATIONAL);
  81. act->do_shutdown();
  82. sup->do_process();
  83. CHECK(act->event_current == 6);
  84. CHECK(act->event_shutdown_finish == 5);
  85. CHECK(act->event_shutdown_start == 4);
  86. CHECK(act->event_start == 3);
  87. CHECK(act->event_init_finish == 2);
  88. CHECK(act->event_init_start == 1);
  89. REQUIRE(destroyed == 0);
  90. REQUIRE(act->get_state() == r::state_t::SHUT_DOWN);
  91. act.reset();
  92. REQUIRE(destroyed == 1);
  93. /* for asan */
  94. sup->do_shutdown();
  95. sup->do_process();
  96. REQUIRE(sup->get_state() == r::state_t::SHUT_DOWN);
  97. REQUIRE(sup->get_leader_queue().size() == 0);
  98. REQUIRE(sup->get_points().size() == 0);
  99. CHECK(rt::empty(sup->get_subscription()));
  100. }
  101. TEST_CASE("fail shutdown test", "[actor]") {
  102. r::system_context_t system_context;
  103. auto sup = system_context.create_supervisor<custom_supervisor_t>().timeout(rt::default_timeout).finish();
  104. auto act = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  105. sup->do_process();
  106. REQUIRE(sup->get_state() == r::state_t::OPERATIONAL);
  107. REQUIRE(sup->active_timers.size() == 0);
  108. act->access<rt::to::resources>()->acquire();
  109. act->do_shutdown();
  110. sup->do_process();
  111. REQUIRE(sup->active_timers.size() == 1); // "init child + shutdown children"
  112. auto timer_it = *sup->active_timers.begin();
  113. sup->do_invoke_timer(timer_it->request_id);
  114. sup->do_process();
  115. REQUIRE(sup->get_children_count() == 1);
  116. CHECK(act->get_state() == r::state_t::SHUTTING_DOWN);
  117. auto id = &std::as_const(custom_child_manager_t::class_identity);
  118. auto plugin = static_cast<r::actor_base_t &>(*sup).access<rt::to::get_plugin>(id);
  119. auto cm_plugin = static_cast<custom_child_manager_t *>(plugin);
  120. REQUIRE(cm_plugin->fail_addr == act->get_address());
  121. auto &ec = cm_plugin->fail_ec;
  122. REQUIRE(ec);
  123. CHECK(ec->ec.value() == static_cast<int>(r::error_code_t::request_timeout));
  124. REQUIRE(!ec->next);
  125. act->access<rt::to::resources>()->release();
  126. act->shutdown_continue();
  127. sup->do_shutdown();
  128. sup->do_process();
  129. REQUIRE(sup->get_children_count() == 0);
  130. CHECK(act->get_state() == r::state_t::SHUT_DOWN);
  131. CHECK(sup->get_state() == r::state_t::SHUT_DOWN);
  132. CHECK(sup->get_leader_queue().size() == 0);
  133. CHECK(sup->get_points().size() == 0);
  134. CHECK(rt::empty(sup->get_subscription()));
  135. }
  136. TEST_CASE("fail initialize test", "[actor]") {
  137. r::system_context_t system_context;
  138. auto sup = system_context.create_supervisor<custom_supervisor_t>().timeout(rt::default_timeout).finish();
  139. sup->do_process();
  140. auto act = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  141. act->access<rt::to::resources>()->acquire();
  142. CHECK(act->access<rt::to::resources>()->has() == 1);
  143. sup->do_process();
  144. REQUIRE(sup->get_children_count() == 2); // sup + actor
  145. REQUIRE(act->get_state() == r::state_t::INITIALIZING);
  146. REQUIRE(sup->active_timers.size() == 1);
  147. auto timer_it = *sup->active_timers.begin();
  148. sup->do_invoke_timer(timer_it->request_id);
  149. act->access<rt::to::resources>()->release();
  150. sup->do_process();
  151. REQUIRE(sup->get_children_count() == 1); // just sup
  152. sup->do_shutdown();
  153. sup->do_process();
  154. CHECK(act->get_state() == r::state_t::SHUT_DOWN);
  155. CHECK(sup->get_state() == r::state_t::SHUT_DOWN);
  156. }
  157. TEST_CASE("double shutdown test (actor)", "[actor]") {
  158. r::system_context_t system_context;
  159. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  160. auto act = sup->create_actor<sample_actor_t>().timeout(rt::default_timeout).finish();
  161. sup->do_process();
  162. act->do_shutdown();
  163. act->do_shutdown();
  164. sup->do_process();
  165. CHECK(act->event_current == 6);
  166. CHECK(act->event_shutdown_finish == 5);
  167. CHECK(act->event_shutdown_start == 4);
  168. REQUIRE(sup->get_children_count() == 1); // just sup
  169. sup->do_shutdown();
  170. sup->do_process();
  171. }
  172. TEST_CASE("double shutdown test (supervisor)", "[actor]") {
  173. r::system_context_t system_context;
  174. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  175. /* auto act = */ sup->create_actor<sample_actor_t>().timeout(rt::default_timeout).finish();
  176. sup->do_process();
  177. sup->do_shutdown();
  178. sup->do_shutdown();
  179. sup->do_process();
  180. REQUIRE(sup->get_children_count() == 0);
  181. REQUIRE(sup->active_timers.size() == 0);
  182. }
  183. TEST_CASE("autoshutdown supervisor", "[actor]") {
  184. r::system_context_t system_context;
  185. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  186. auto act = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).autoshutdown_supervisor().finish();
  187. sup->do_process();
  188. CHECK(act->get_state() == r::state_t::OPERATIONAL);
  189. CHECK(sup->get_state() == r::state_t::OPERATIONAL);
  190. act->do_shutdown();
  191. sup->do_process();
  192. CHECK(act->get_state() == r::state_t::SHUT_DOWN);
  193. CHECK(sup->get_state() == r::state_t::SHUT_DOWN);
  194. }
  195. TEST_CASE("escalate failure", "[actor]") {
  196. r::system_context_t system_context;
  197. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  198. auto act = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).escalate_failure().finish();
  199. sup->do_process();
  200. CHECK(act->get_state() == r::state_t::OPERATIONAL);
  201. CHECK(sup->get_state() == r::state_t::OPERATIONAL);
  202. auto ec = r::make_error_code(r::error_code_t::cancelled);
  203. auto ee = r::make_error("ctx", ec);
  204. act->do_shutdown(ee);
  205. sup->do_process();
  206. CHECK(act->get_state() == r::state_t::SHUT_DOWN);
  207. CHECK(sup->get_state() == r::state_t::SHUT_DOWN);
  208. }