Browse Source

Add custom on process exit callback.

Roberto Ostinelli 5 years ago
parent
commit
70051ed799
4 changed files with 87 additions and 24 deletions
  1. 19 1
      src/syn_event_handler.erl
  2. 20 21
      src/syn_registry.erl
  3. 36 2
      test/syn_registry_SUITE.erl
  4. 12 0
      test/syn_test_event_handler.erl

+ 19 - 1
src/syn_event_handler.erl

@@ -28,6 +28,7 @@
 %% ==========================================================================================================
 %% ==========================================================================================================
 -module(syn_event_handler).
 -module(syn_event_handler).
 
 
+-export([do_on_process_exit/5]).
 -export([do_resolve_registry_conflict/4]).
 -export([do_resolve_registry_conflict/4]).
 
 
 -callback on_process_exit(
 -callback on_process_exit(
@@ -52,6 +53,23 @@
 
 
 -optional_callbacks([on_process_exit/4, on_group_process_exit/4, resolve_registry_conflict/3]).
 -optional_callbacks([on_process_exit/4, on_group_process_exit/4, resolve_registry_conflict/3]).
 
 
+-spec do_on_process_exit(
+    Name :: any(),
+    Pid :: pid(),
+    Meta :: any(),
+    Reason :: any(),
+    CustomEventHandler :: module()
+) -> any().
+do_on_process_exit(Name, Pid, Meta, Reason, CustomEventHandler) ->
+    spawn(fun() ->
+        case erlang:function_exported(CustomEventHandler, on_process_exit, 4) of
+            true ->
+                CustomEventHandler:on_process_exit(Name, Pid, Meta, Reason);
+            _ ->
+                ok
+        end
+    end).
+
 -spec do_resolve_registry_conflict(
 -spec do_resolve_registry_conflict(
     Name :: any(),
     Name :: any(),
     {Pid1 :: pid(), Meta1 :: any()},
     {Pid1 :: pid(), Meta1 :: any()},
@@ -68,7 +86,7 @@ do_resolve_registry_conflict(Name, {LocalPid, LocalMeta}, {RemotePid, RemoteMeta
                     undefined
                     undefined
             catch Class:Reason:Stacktrace ->
             catch Class:Reason:Stacktrace ->
                 error_logger:error_msg(
                 error_logger:error_msg(
-                    "Syn(~p): Error in custom handler while selecting process to keep: ~p:~p:~p",
+                    "Syn(~p): Error in custom handler resolve_registry_conflict: ~p:~p:~p",
                     [node(), Class, Reason, Stacktrace]
                     [node(), Class, Reason, Stacktrace]
                 ),
                 ),
                 undefined
                 undefined

+ 20 - 21
src/syn_registry.erl

@@ -252,14 +252,16 @@ handle_info({'DOWN', _MonitorRef, process, Pid, Reason}, State) ->
     case find_processes_entry_by_pid(Pid) of
     case find_processes_entry_by_pid(Pid) of
         [] ->
         [] ->
             %% log
             %% log
-            log_process_exit(undefined, Pid, Reason);
+            handle_process_exit(undefined, Pid, undefined, Reason, State);
 
 
         Entries ->
         Entries ->
             lists:foreach(fun(Entry) ->
             lists:foreach(fun(Entry) ->
                 %% get process info
                 %% get process info
                 Name = Entry#syn_registry_table.name,
                 Name = Entry#syn_registry_table.name,
+                Pid = Entry#syn_registry_table.pid,
+                Meta = Entry#syn_registry_table.meta,
                 %% log
                 %% log
-                log_process_exit(Name, Pid, Reason),
+                handle_process_exit(Name, Pid, Meta, Reason, State),
                 %% remove from table
                 %% remove from table
                 remove_from_local_table(Name),
                 remove_from_local_table(Name),
                 %% multicast
                 %% multicast
@@ -327,6 +329,7 @@ register_on_node(Name, Pid, Meta) ->
             Entry#syn_registry_table.monitor_ref
             Entry#syn_registry_table.monitor_ref
     end,
     end,
     %% add to table
     %% add to table
+
     add_to_local_table(Name, Pid, Meta, MonitorRef).
     add_to_local_table(Name, Pid, Meta, MonitorRef).
 
 
 -spec unregister_on_node(Name :: any()) -> ok | {error, Reason :: any()}.
 -spec unregister_on_node(Name :: any()) -> ok | {error, Reason :: any()}.
@@ -367,26 +370,22 @@ find_process_entry_by_name(Name) ->
         _ -> undefined
         _ -> undefined
     end.
     end.
 
 
--spec log_process_exit(Name :: any(), Pid :: pid(), Reason :: any()) -> ok.
-log_process_exit(Name, Pid, Reason) ->
-    case Reason of
-        normal -> ok;
-        shutdown -> ok;
-        {shutdown, _} -> ok;
-        killed -> ok;
+-spec handle_process_exit(Name :: any(), Pid :: pid(), Meta :: any(), Reason :: any(), #state{}) -> ok.
+handle_process_exit(Name, Pid, Meta, Reason, #state{
+    custom_event_handler = CustomEventHandler
+}) ->
+    case Name of
+        undefined ->
+            error_logger:error_msg(
+                "Syn(~p): Received a DOWN message from an unmonitored process ~p with reason: ~p~n",
+                [node(), Pid, Reason]
+            );
         _ ->
         _ ->
-            case Name of
-                undefined ->
-                    error_logger:error_msg(
-                        "Syn(~p): Received a DOWN message from an unmonitored process ~p with reason: ~p~n",
-                        [node(), Pid, Reason]
-                    );
-                _ ->
-                    error_logger:error_msg(
-                        "Syn(~p): Process with name ~p and pid ~p exited with reason: ~p~n",
-                        [node(), Name, Pid, Reason]
-                    )
-            end
+            error_logger:error_msg(
+                "Syn(~p): Process with name ~p and pid ~p exited with reason: ~p~n",
+                [node(), Name, Pid, Reason]
+            ),
+            syn_event_handler:do_on_process_exit(Name, Pid, Meta, Reason, CustomEventHandler)
     end.
     end.
 
 
 -spec sync_registry_tuples(RemoteNode :: node(), RegistryTuples :: [syn_registry_tuple()], #state{}) -> ok.
 -spec sync_registry_tuples(RemoteNode :: node(), RegistryTuples :: [syn_registry_tuple()], #state{}) -> ok.

+ 36 - 2
test/syn_registry_SUITE.erl

@@ -37,7 +37,8 @@
     single_node_register_and_unregister/1,
     single_node_register_and_unregister/1,
     single_node_registration_errors/1,
     single_node_registration_errors/1,
     single_node_registry_count/1,
     single_node_registry_count/1,
-    single_node_register_gen_server/1
+    single_node_register_gen_server/1,
+    single_node_callback_on_process_exit/1
 ]).
 ]).
 -export([
 -export([
     two_nodes_register_monitor_and_unregister/1,
     two_nodes_register_monitor_and_unregister/1,
@@ -97,7 +98,8 @@ groups() ->
             single_node_register_and_unregister,
             single_node_register_and_unregister,
             single_node_registration_errors,
             single_node_registration_errors,
             single_node_registry_count,
             single_node_registry_count,
-            single_node_register_gen_server
+            single_node_register_gen_server,
+            single_node_callback_on_process_exit
         ]},
         ]},
         {two_nodes_process_registration, [shuffle], [
         {two_nodes_process_registration, [shuffle], [
             two_nodes_register_monitor_and_unregister,
             two_nodes_register_monitor_and_unregister,
@@ -312,6 +314,38 @@ single_node_register_gen_server(_Config) ->
     %% send via syn
     %% send via syn
     {badarg, {syn_test_gen_server, anything}} = (catch syn:send(syn_test_gen_server, anything)).
     {badarg, {syn_test_gen_server, anything}} = (catch syn:send(syn_test_gen_server, anything)).
 
 
+single_node_callback_on_process_exit(_Config) ->
+    %% use custom handler
+    syn_test_suite_helper:use_custom_handler(),
+    %% start
+    ok = syn:start(),
+    %% start process
+    Pid = syn_test_suite_helper:start_process(),
+    Pid2 = syn_test_suite_helper:start_process(),
+    %% register
+    TestPid = self(),
+    ok = syn:register(<<"my proc">>, Pid, {pid, TestPid}),
+    ok = syn:register(<<"my proc 2">>, Pid2, {pid2, TestPid}),
+    %% kill 1
+    syn_test_suite_helper:kill_process(Pid),
+    receive
+        {received_event_on, pid} ->
+            ok;
+        {received_event_on, pid2} ->
+            ok = callback_on_process_exit_was_received_by_pid2
+    after 1000 ->
+        ok = callback_on_process_exit_was_not_received_by_pid
+    end,
+    %% unregister & kill 2
+    ok = syn:unregister(<<"my proc 2">>),
+    syn_test_suite_helper:kill_process(Pid2),
+    receive
+        {received_event_on, pid2} ->
+            ok = callback_on_process_exit_was_received_by_pid2
+    after 1000 ->
+        ok
+    end.
+
 two_nodes_register_monitor_and_unregister(Config) ->
 two_nodes_register_monitor_and_unregister(Config) ->
     %% get slave
     %% get slave
     SlaveNode = proplists:get_value(slave_node, Config),
     SlaveNode = proplists:get_value(slave_node, Config),

+ 12 - 0
test/syn_test_event_handler.erl

@@ -27,8 +27,20 @@
 -behaviour(syn_event_handler).
 -behaviour(syn_event_handler).
 
 
 %% API
 %% API
+-export([on_process_exit/4]).
 -export([resolve_registry_conflict/3]).
 -export([resolve_registry_conflict/3]).
 
 
+-spec on_process_exit(
+    Name :: any(),
+    Pid :: pid(),
+    Meta :: any(),
+    Reason :: any()
+) -> any().
+on_process_exit(_Name, _Pid, {PidId, TestPid}, _Reason) ->
+    TestPid ! {received_event_on, PidId};
+on_process_exit(_Name, _Pid, _Meta, _Reason) ->
+    ok.
+
 -spec resolve_registry_conflict(
 -spec resolve_registry_conflict(
     Name :: any(),
     Name :: any(),
     {Pid1 :: pid(), Meta1 :: any()},
     {Pid1 :: pid(), Meta1 :: any()},