Browse Source

Add updated callbacks.

Roberto Ostinelli 3 years ago
parent
commit
3391e74fe6

+ 49 - 63
src/syn_event_handler.erl

@@ -30,8 +30,7 @@
 
 %% API
 -export([ensure_event_handler_loaded/0]).
--export([do_on_process_registered/4, do_on_process_unregistered/4]).
--export([do_on_process_joined/4, do_on_process_left/4]).
+-export([call_event_handler/2]).
 -export([do_resolve_registry_conflict/4]).
 
 -callback on_process_registered(
@@ -41,6 +40,13 @@
     Meta :: any()
 ) -> any().
 
+-callback on_registry_process_updated(
+    Scope :: any(),
+    Name :: any(),
+    Pid :: pid(),
+    Meta :: any()
+) -> any().
+
 -callback on_process_unregistered(
     Scope :: any(),
     Name :: any(),
@@ -48,13 +54,36 @@
     Meta :: any()
 ) -> any().
 
+-callback on_process_joined(
+    Scope :: any(),
+    GroupName :: any(),
+    Pid :: pid(),
+    Meta :: any()
+) -> any().
+
+-callback on_group_process_updated(
+    Scope :: any(),
+    GroupName :: any(),
+    Pid :: pid(),
+    Meta :: any()
+) -> any().
+
+-callback on_process_left(
+    Scope :: any(),
+    GroupName :: any(),
+    Pid :: pid(),
+    Meta :: any()
+) -> any().
+
 -callback resolve_registry_conflict(
     Name :: any(),
     {Pid1 :: pid(), Meta1 :: any()},
     {Pid2 :: pid(), Meta2 :: any()}
 ) -> PidToKeep :: pid() | undefined.
 
--optional_callbacks([on_process_registered/4, on_process_unregistered/4, resolve_registry_conflict/3]).
+-optional_callbacks([on_process_registered/4, on_registry_process_updated/4, on_process_unregistered/4]).
+-optional_callbacks([on_process_joined/4, on_group_process_updated/4, on_process_left/4]).
+-optional_callbacks([resolve_registry_conflict/3]).
 
 %% ===================================================================
 %% API
@@ -66,45 +95,25 @@ ensure_event_handler_loaded() ->
     %% ensure that is it loaded (not using code:ensure_loaded/1 to support embedded mode)
     catch CustomEventHandler:module_info(exports).
 
--spec do_on_process_registered(
-    Scope :: atom(),
-    Name :: any(),
-    {TablePid :: pid() | undefined, TableMeta :: any()},
-    {Pid :: pid(), Meta :: any()}
-) -> any().
-do_on_process_registered(_Scope, _Name, {TablePid, TableMeta}, {Pid, Meta})
-    when TablePid =:= Pid, TableMeta =:= Meta -> ok;
-do_on_process_registered(Scope, Name, {_TablePid, _TableMeta}, {Pid, Meta}) ->
-    call_callback_event(on_process_registered, Scope, Name, Pid, Meta).
-
--spec do_on_process_unregistered(
-    Scope :: atom(),
-    Name :: any(),
-    TablePid :: pid(),
-    TableMeta :: any()
-) -> any().
-do_on_process_unregistered(Scope, Name, Pid, Meta) ->
-    call_callback_event(on_process_unregistered, Scope, Name, Pid, Meta).
-
--spec do_on_process_joined(
-    Scope :: atom(),
-    Name :: any(),
-    {TablePid :: pid() | undefined, TableMeta :: any()},
-    {Pid :: pid(), Meta :: any()}
+-spec call_event_handler(
+    CallbackMethod :: atom(),
+    Args :: [any()]
 ) -> any().
-do_on_process_joined(_Scope, _GroupName, {TableMeta}, {_Pid, Meta})
-    when TableMeta =:= Meta -> ok;
-do_on_process_joined(Scope, GroupName, {_TableMeta}, {Pid, Meta}) ->
-    call_callback_event(on_process_joined, Scope, GroupName, Pid, Meta).
+call_event_handler(CallbackMethod, Args) ->
+    CustomEventHandler = get_custom_event_handler(),
+    case erlang:function_exported(CustomEventHandler, CallbackMethod, 4) of
+        true ->
+            try apply(CustomEventHandler, CallbackMethod, Args)
+            catch Class:Reason:Stacktrace ->
+                error_logger:error_msg(
+                    "Syn(~p): Error ~p:~p in custom handler ~p: ~p",
+                    [node(), Class, Reason, CallbackMethod, Stacktrace]
+                )
+            end;
 
--spec do_on_process_left(
-    Scope :: atom(),
-    Name :: any(),
-    TablePid :: pid(),
-    TableMeta :: any()
-) -> any().
-do_on_process_left(Scope, GroupName, Pid, Meta) ->
-    call_callback_event(on_process_left, Scope, GroupName, Pid, Meta).
+        _ ->
+            ok
+    end.
 
 -spec do_resolve_registry_conflict(
     Scope :: atom(),
@@ -145,26 +154,3 @@ do_resolve_registry_conflict(Scope, Name, {Pid1, Meta1, Time1}, {Pid2, Meta2, Ti
 -spec get_custom_event_handler() -> undefined | {ok, CustomEventHandler :: atom()}.
 get_custom_event_handler() ->
     application:get_env(syn, event_handler, undefined).
-
--spec call_callback_event(
-    CallbackMethod :: atom(),
-    Scope :: atom(),
-    Name :: any(),
-    Pid :: pid(),
-    Meta :: any()
-) -> any().
-call_callback_event(CallbackMethod, Scope, Name, Pid, Meta) ->
-    CustomEventHandler = get_custom_event_handler(),
-    case erlang:function_exported(CustomEventHandler, CallbackMethod, 4) of
-        true ->
-            try CustomEventHandler:CallbackMethod(Scope, Name, Pid, Meta)
-            catch Class:Reason:Stacktrace ->
-                error_logger:error_msg(
-                    "Syn(~p): Error ~p:~p in custom handler ~p: ~p",
-                    [node(), Class, Reason, CallbackMethod, Stacktrace]
-                )
-            end;
-
-        _ ->
-            ok
-    end.

+ 51 - 34
src/syn_groups.erl

@@ -105,11 +105,11 @@ join(Scope, GroupName, Pid) when is_pid(Pid) ->
 join(Scope, GroupName, Pid, Meta) ->
     Node = node(Pid),
     case syn_gen_scope:call(?MODULE, Node, Scope, {join_on_owner, node(), GroupName, Pid, Meta}) of
-        {ok, {TableMeta, Time, TableByName, TableByPid}} when Node =/= node() ->
+        {ok, {CallbackMethod, Time, TableByName, TableByPid}} when Node =/= node() ->
             %% update table on caller node immediately so that subsequent calls have an updated registry
             add_to_local_table(GroupName, Pid, Meta, Time, undefined, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_joined(Scope, GroupName, {TableMeta}, {Pid, Meta}),
+            syn_event_handler:call_event_handler(CallbackMethod, [Scope, GroupName, Pid, Meta]),
             %% return
             ok;
 
@@ -130,11 +130,11 @@ leave(Scope, GroupName, Pid) ->
         TableByName ->
             Node = node(Pid),
             case syn_gen_scope:call(?MODULE, Node, Scope, {leave_on_owner, node(), GroupName, Pid}) of
-                {ok, {TableMeta, TableByPid}} when Node =/= node() ->
+                {ok, {Meta, TableByPid}} when Node =/= node() ->
                     %% remove table on caller node immediately so that subsequent calls have an updated registry
                     remove_from_local_table(GroupName, Pid, TableByName, TableByPid),
                     %% callback
-                    syn_event_handler:do_on_process_left(Scope, GroupName, Pid, TableMeta),
+                    syn_event_handler:call_event_handler(on_process_left, [Scope, GroupName, Pid, Meta]),
                     %% return
                     ok;
 
@@ -207,25 +207,39 @@ handle_call({join_on_owner, RequesterNode, GroupName, Pid, Meta}, _From, #state{
 } = State) ->
     case is_process_alive(Pid) of
         true ->
-            %% available
-            MRef = case find_monitor_for_pid(Pid, TableByPid) of
-                undefined -> erlang:monitor(process, Pid);  %% process is not monitored yet, add
-                MRef0 -> MRef0
-            end,
-            %% get table meta
-            TableMeta = case find_groups_entry_by_name_and_pid(GroupName, Pid, TableByName) of
-                {{_, M}, _, _, _, _} -> M;
-                _ -> undefined
-            end,
-            %% add to local table
-            Time = erlang:system_time(),
-            add_to_local_table(GroupName, Pid, Meta, Time, MRef, TableByName, TableByPid),
-            %% callback
-            syn_event_handler:do_on_process_joined(Scope, GroupName, {TableMeta}, {Pid, Meta}),
-            %% broadcast
-            syn_gen_scope:broadcast({'3.0', sync_join, GroupName, Pid, Meta, Time}, [RequesterNode], State),
-            %% return
-            {reply, {ok, {TableMeta, Time, TableByName, TableByPid}}, State};
+            case find_groups_entry_by_name_and_pid(GroupName, Pid, TableByName) of
+                undefined ->
+                    %% add
+                    MRef = case find_monitor_for_pid(Pid, TableByPid) of
+                        undefined -> erlang:monitor(process, Pid);  %% process is not monitored yet, create
+                        MRef0 -> MRef0
+                    end,
+                    Time = erlang:system_time(),
+                    %% add to local table
+                    add_to_local_table(GroupName, Pid, Meta, Time, MRef, TableByName, TableByPid),
+                    %% callback
+                    syn_event_handler:call_event_handler(on_process_joined, [Scope, GroupName, Pid, Meta]),
+                    %% broadcast
+                    syn_gen_scope:broadcast({'3.0', sync_join, GroupName, Pid, Meta, Time}, [RequesterNode], State),
+                    %% return
+                    {reply, {ok, {on_process_joined, Time, TableByName, TableByPid}}, State};
+
+                {{_, Meta}, _, _, _, _} ->
+                    %% re-joined with same meta
+                    {ok, noop};
+
+                {{_, _}, _, _, MRef, _} ->
+                    %% meta updated
+                    Time = erlang:system_time(),
+                    %% add to local table
+                    add_to_local_table(GroupName, Pid, Meta, Time, MRef, TableByName, TableByPid),
+                    %% callback
+                    syn_event_handler:call_event_handler(on_group_process_updated, [Scope, GroupName, Pid, Meta]),
+                    %% broadcast
+                    syn_gen_scope:broadcast({'3.0', sync_join, GroupName, Pid, Meta, Time}, [RequesterNode], State),
+                    %% return
+                    {reply, {ok, {on_group_process_updated, Time, TableByName, TableByPid}}, State}
+            end;
 
         false ->
             {reply, {{error, not_alive}, undefined}, State}
@@ -240,17 +254,17 @@ handle_call({leave_on_owner, RequesterNode, GroupName, Pid}, _From, #state{
         undefined ->
             {reply, {{error, not_in_group}, undefined}, State};
 
-        {{_, _}, TableMeta, _, _, _} ->
+        {{_, _}, Meta, _, _, _} ->
             %% is this the last group process is in?
             maybe_demonitor(Pid, TableByPid),
             %% remove from table
             remove_from_local_table(GroupName, Pid, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_left(Scope, GroupName, Pid, TableMeta),
+            syn_event_handler:call_event_handler(on_process_left, [Scope, GroupName, Pid, Meta]),
             %% broadcast
-            syn_gen_scope:broadcast({'3.0', sync_leave, GroupName, Pid, TableMeta}, [RequesterNode], State),
+            syn_gen_scope:broadcast({'3.0', sync_leave, GroupName, Pid, Meta}, [RequesterNode], State),
             %% return
-            {reply, {ok, {TableMeta, TableByPid}}, State}
+            {reply, {ok, {Meta, TableByPid}}, State}
     end;
 
 handle_call(Request, From, State) ->
@@ -276,7 +290,7 @@ handle_info({'3.0', sync_leave, GroupName, Pid, Meta}, #state{
     %% remove from table
     remove_from_local_table(GroupName, Pid, TableByName, TableByPid),
     %% callback
-    syn_event_handler:do_on_process_left(Scope, GroupName, Pid, Meta),
+    syn_event_handler:call_event_handler(on_process_left, [Scope, GroupName, Pid, Meta]),
     %% return
     {noreply, State};
 
@@ -297,7 +311,7 @@ handle_info({'DOWN', _MRef, process, Pid, Reason}, #state{
                 %% remove from table
                 remove_from_local_table(GroupName, Pid, TableByName, TableByPid),
                 %% callback
-                syn_event_handler:do_on_process_left(Scope, GroupName, Pid, Meta),
+                syn_event_handler:call_event_handler(on_process_left, [Scope, GroupName, Pid, Meta]),
                 %% broadcast
                 syn_gen_scope:broadcast({'3.0', sync_leave, GroupName, Pid, Meta}, State)
             end, Entries)
@@ -451,7 +465,7 @@ purge_groups_for_remote_node(Scope, Node, TableByName, TableByPid) ->
     GroupsTuples = get_groups_tuples_for_node(Node, TableByName),
     spawn(fun() ->
         lists:foreach(fun({GroupName, Pid, Meta, _Time}) ->
-            syn_event_handler:do_on_process_left(Scope, GroupName, Pid, Meta)
+            syn_event_handler:call_event_handler(on_process_left, [Scope, GroupName, Pid, Meta])
         end, GroupsTuples)
     end),
     ets:match_delete(TableByName, {{'_', '_'}, '_', '_', '_', Node}),
@@ -474,13 +488,16 @@ handle_groups_sync(GroupName, Pid, Meta, Time, #state{
             %% new
             add_to_local_table(GroupName, Pid, Meta, Time, undefined, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_joined(Scope, GroupName, {undefined}, {Pid, Meta});
+            syn_event_handler:call_event_handler(on_process_joined, [Scope, GroupName, Pid, Meta]);
 
         {{GroupName, Pid}, TableMeta, TableTime, _MRef, _TableNode} when Time > TableTime ->
-            %% update meta
+            %% maybe updated meta or time only
             add_to_local_table(GroupName, Pid, Meta, Time, undefined, TableByName, TableByPid),
-            %% callback
-            syn_event_handler:do_on_process_joined(Scope, GroupName, {TableMeta}, {Pid, Meta});
+            %% callback (call only if meta update)
+            case TableMeta =/= Meta of
+                true -> syn_event_handler:call_event_handler(on_group_process_updated, [Scope, GroupName, Pid, Meta]);
+                _ -> ok
+            end;
 
         {{GroupName, Pid}, _TableMeta, _TableTime, _TableMRef, _TableNode} ->
             %% race condition: incoming data is older, ignore

+ 29 - 21
src/syn_registry.erl

@@ -96,11 +96,11 @@ register(Scope, Name, Pid) when is_pid(Pid) ->
 register(Scope, Name, Pid, Meta) ->
     Node = node(Pid),
     case syn_gen_scope:call(?MODULE, Node, Scope, {register_on_owner, node(), Name, Pid, Meta}) of
-        {ok, {TablePid, TableMeta, Time, TableByName, TableByPid}} when Node =/= node() ->
+        {ok, {CallbackMethod, Time, TableByName, TableByPid}} when Node =/= node() ->
             %% update table on caller node immediately so that subsequent calls have an updated registry
             add_to_local_table(Name, Pid, Meta, Time, undefined, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_registered(Scope, Name, {TablePid, TableMeta}, {Pid, Meta}),
+            syn_event_handler:call_event_handler(CallbackMethod, [Scope, Name, Pid, Meta]),
             %% return
             ok;
 
@@ -131,7 +131,7 @@ unregister(Scope, Name) ->
                             %% remove table on caller node immediately so that subsequent calls have an updated registry
                             remove_from_local_table(Name, Pid, TableByName, TableByPid),
                             %% callback
-                            syn_event_handler:do_on_process_unregistered(Scope, Name, Pid, Meta),
+                            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, Pid, Meta]),
                             %% return
                             ok;
 
@@ -206,22 +206,26 @@ handle_call({register_on_owner, RequesterNode, Name, Pid, Meta}, _From, #state{
                     Time = erlang:system_time(),
                     add_to_local_table(Name, Pid, Meta, Time, MRef, TableByName, TableByPid),
                     %% callback
-                    syn_event_handler:do_on_process_registered(Scope, Name, {undefined, undefined}, {Pid, Meta}),
+                    syn_event_handler:call_event_handler(on_process_registered, [Scope, Name, Pid, Meta]),
                     %% broadcast
                     syn_gen_scope:broadcast({'3.0', sync_register, Name, Pid, Meta, Time}, [RequesterNode], State),
                     %% return
-                    {reply, {ok, {undefined, undefined, Time, TableByName, TableByPid}}, State};
+                    {reply, {ok, {on_process_registered, Time, TableByName, TableByPid}}, State};
 
-                {Name, Pid, TableMeta, _TableTime, MRef, _TableNode} ->
-                    %% same pid, possibly new meta or time, overwrite
+                {Name, Pid, Meta, _, _, _} ->
+                    %% same pid, same meta
+                    {reply, {ok, noop}, State};
+
+                {Name, Pid, _, _, MRef, _} ->
+                    %% same pid, new meta
                     Time = erlang:system_time(),
                     add_to_local_table(Name, Pid, Meta, Time, MRef, TableByName, TableByPid),
                     %% callback
-                    syn_event_handler:do_on_process_registered(Scope, Name, {Pid, TableMeta}, {Pid, Meta}),
+                    syn_event_handler:call_event_handler(on_registry_process_updated, [Scope, Name, Pid, Meta]),
                     %% broadcast
                     syn_gen_scope:broadcast({'3.0', sync_register, Name, Pid, Meta, Time}, State),
                     %% return
-                    {reply, {ok, {Pid, TableMeta, Time, TableByName, TableByPid}}, State};
+                    {reply, {ok, {on_registry_process_updated, Time, TableByName, TableByPid}}, State};
 
                 _ ->
                     {reply, {{error, taken}, undefined}, State}
@@ -243,7 +247,7 @@ handle_call({unregister_on_owner, RequesterNode, Name, Pid}, _From, #state{
             %% remove from table
             remove_from_local_table(Name, Pid, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_unregistered(Scope, Name, Pid, Meta),
+            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, Pid, Meta]),
             %% broadcast
             syn_gen_scope:broadcast({'3.0', sync_unregister, Name, Pid, Meta}, [RequesterNode], State),
             %% return
@@ -279,7 +283,7 @@ handle_info({'3.0', sync_unregister, Name, Pid, Meta}, #state{
 } = State) ->
     remove_from_local_table(Name, Pid, TableByName, TableByPid),
     %% callback
-    syn_event_handler:do_on_process_unregistered(Scope, Name, Pid, Meta),
+    syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, Pid, Meta]),
     %% return
     {noreply, State};
 
@@ -300,7 +304,7 @@ handle_info({'DOWN', _MRef, process, Pid, Reason}, #state{
                 %% remove from table
                 remove_from_local_table(Name, Pid, TableByName, TableByPid),
                 %% callback
-                syn_event_handler:do_on_process_unregistered(Scope, Name, Pid, Meta),
+                syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, Pid, Meta]),
                 %% broadcast
                 syn_gen_scope:broadcast({'3.0', sync_unregister, Name, Pid, Meta}, State)
             end, Entries)
@@ -469,7 +473,7 @@ purge_registry_for_remote_node(Scope, Node, TableByName, TableByPid) when Node =
     RegistryTuples = get_registry_tuples_for_node(Node, TableByName),
     spawn(fun() ->
         lists:foreach(fun({Name, Pid, Meta, _Time}) ->
-            syn_event_handler:do_on_process_unregistered(Scope, Name, Pid, Meta)
+            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, Pid, Meta])
         end, RegistryTuples)
     end),
     %% remove all from pid table
@@ -493,13 +497,17 @@ handle_registry_sync(Name, Pid, Meta, Time, #state{
             %% no conflict
             add_to_local_table(Name, Pid, Meta, Time, undefined, TableByName, TableByPid),
             %% callback
-            syn_event_handler:do_on_process_registered(Scope, Name, {undefined, undefined}, {Pid, Meta});
+            syn_event_handler:call_event_handler(on_process_registered, [Scope, Name, Pid, Meta]);
 
         {Name, Pid, TableMeta, _TableTime, MRef, _TableNode} ->
             %% same pid, more recent (because it comes from the same node, which means that it's sequential)
+            %% maybe updated meta or time only
             add_to_local_table(Name, Pid, Meta, Time, MRef, TableByName, TableByPid),
-            %% callback
-            syn_event_handler:do_on_process_registered(Scope, Name, {Pid, TableMeta}, {Pid, Meta});
+            %% callback (call only if meta update)
+            case TableMeta =/= Meta of
+                true -> syn_event_handler:call_event_handler(on_registry_process_updated, [Scope, Name, Pid, Meta]);
+                _ -> ok
+            end;
 
         {Name, TablePid, TableMeta, TableTime, TableMRef, _TableNode} when node(TablePid) =:= node() ->
             %% current node runs a conflicting process -> resolve
@@ -513,8 +521,8 @@ handle_registry_sync(Name, Pid, Meta, Time, #state{
             %% current node does not own any of the conflicting processes, update
             update_local_table(Name, TablePid, {Pid, Meta, Time, undefined}, TableByName, TableByPid),
             %% callbacks
-            syn_event_handler:do_on_process_unregistered(Scope, Name, TablePid, TableMeta),
-            syn_event_handler:do_on_process_registered(Scope, Name, {TablePid, TableMeta}, {Pid, Meta});
+            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, TablePid, TableMeta]),
+            syn_event_handler:call_event_handler(on_process_registered, [Scope, Name, Pid, Meta]);
 
         {Name, _TablePid, _TableMeta, _TableTime, _TableMRef, _TableNode} ->
             %% race condition: incoming data is older, ignore
@@ -551,8 +559,8 @@ resolve_conflict(Scope, Name, {Pid, Meta, Time}, {TablePid, TableMeta, TableTime
             %% kill
             exit(TablePid, {syn_resolve_kill, Name, TableMeta}),
             %% callbacks
-            syn_event_handler:do_on_process_unregistered(Scope, Name, TablePid, TableMeta),
-            syn_event_handler:do_on_process_registered(Scope, Name, {TablePid, TableMeta}, {Pid, Meta});
+            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, TablePid, TableMeta]),
+            syn_event_handler:call_event_handler(on_process_registered, [Scope, Name, Pid, Meta]);
 
         TablePid ->
             %% -> we keep the local pid
@@ -575,5 +583,5 @@ resolve_conflict(Scope, Name, {Pid, Meta, Time}, {TablePid, TableMeta, TableTime
             %% kill local, remote will be killed by other node performing the same resolve
             exit(TablePid, {syn_resolve_kill, Name, TableMeta}),
             %% callback
-            syn_event_handler:do_on_process_unregistered(Scope, Name, TablePid, TableMeta)
+            syn_event_handler:call_event_handler(on_process_unregistered, [Scope, Name, TablePid, TableMeta])
     end.

+ 15 - 4
test/syn_groups_SUITE.erl

@@ -1302,13 +1302,24 @@ three_nodes_custom_event_handler_joined_left(Config) ->
     syn_test_suite_helper:assert_empty_queue(self()),
 
     %% ---> on meta update
-    ok = syn:join("my-group", Pid, {recipient, self(), <<"new-meta">>}),
+    ok = syn:join("my-group", Pid, {recipient, self(), <<"new-meta-0">>}),
 
     %% check callbacks called
     syn_test_suite_helper:assert_received_messages([
-        {on_process_joined, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
-        {on_process_joined, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
-        {on_process_joined, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
+        {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta-0">>},
+        {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta-0">>},
+        {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta-0">>}
+    ]),
+    syn_test_suite_helper:assert_empty_queue(self()),
+
+    %% update meta from another node
+    ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid, {recipient, self(), <<"new-meta">>}]),
+
+    %% check callbacks called
+    syn_test_suite_helper:assert_received_messages([
+        {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
+        {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
+        {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
     ]),
     syn_test_suite_helper:assert_empty_queue(self()),
 

+ 3 - 3
test/syn_registry_SUITE.erl

@@ -1247,9 +1247,9 @@ three_nodes_custom_event_handler_reg_unreg(Config) ->
 
     %% check callbacks called
     syn_test_suite_helper:assert_received_messages([
-        {on_process_registered, CurrentNode, default, "proc-handler", Pid, <<"new-meta">>},
-        {on_process_registered, SlaveNode1, default, "proc-handler", Pid, <<"new-meta">>},
-        {on_process_registered, SlaveNode2, default, "proc-handler", Pid, <<"new-meta">>}
+        {on_registry_process_updated, CurrentNode, default, "proc-handler", Pid, <<"new-meta">>},
+        {on_registry_process_updated, SlaveNode1, default, "proc-handler", Pid, <<"new-meta">>},
+        {on_registry_process_updated, SlaveNode2, default, "proc-handler", Pid, <<"new-meta">>}
     ]),
     syn_test_suite_helper:assert_empty_queue(self()),
 

+ 8 - 0
test/syn_test_event_handler_callbacks.erl

@@ -28,8 +28,10 @@
 
 -export([on_process_registered/4]).
 -export([on_process_unregistered/4]).
+-export([on_registry_process_updated/4]).
 -export([on_process_joined/4]).
 -export([on_process_left/4]).
+-export([on_group_process_updated/4]).
 
 on_process_registered(Scope, Name, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
     RecipientPid ! {on_process_registered, node(), Scope, Name, Pid, AdditionalMeta}.
@@ -37,8 +39,14 @@ on_process_registered(Scope, Name, Pid, {recipient, RecipientPid, AdditionalMeta
 on_process_unregistered(Scope, Name, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
     RecipientPid ! {on_process_unregistered, node(), Scope, Name, Pid, AdditionalMeta}.
 
+on_registry_process_updated(Scope, Name, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
+    RecipientPid ! {on_registry_process_updated, node(), Scope, Name, Pid, AdditionalMeta}.
+
 on_process_joined(Scope, GroupName, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
     RecipientPid ! {on_process_joined, node(), Scope, GroupName, Pid, AdditionalMeta}.
 
 on_process_left(Scope, GroupName, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
     RecipientPid ! {on_process_left, node(), Scope, GroupName, Pid, AdditionalMeta}.
+
+on_group_process_updated(Scope, GroupName, Pid, {recipient, RecipientPid, AdditionalMeta}) ->
+    RecipientPid ! {on_group_process_updated, node(), Scope, GroupName, Pid, AdditionalMeta}.