fix(gateway): register the session process with presence on resume (#1715)

This commit is contained in:
Hampus
2026-08-18 16:06:26 +02:00
committed by GitHub
parent 5ce5669f17
commit 7d82d188a0
3 changed files with 64 additions and 14 deletions
+26 -2
View File
@@ -84,11 +84,14 @@ code_change(_OldVsn, State, _Extra) ->
-spec handle_call(term(), gen_server:from(), state()) ->
{reply, term(), state()} | {stop, normal, ok, state()}.
handle_call({session_connect, Request}, {Pid, _}, State) when is_map(Request), is_pid(Pid) ->
{reply, Reply, NewState} = presence_session:handle_session_connect(Request, Pid, State),
SessionPid = session_connect_pid(Request, Pid),
{reply, Reply, NewState} = presence_session:handle_session_connect(
Request, SessionPid, State
),
FinalState = presence_broadcast:publish_global_presence(
maps:get(sessions, NewState), NewState
),
presence_broadcast:send_cached_presences_to_session(Pid, FinalState),
presence_broadcast:send_cached_presences_to_session(SessionPid, FinalState),
{reply, Reply, FinalState};
handle_call(get_current_visible_presence, _From, State) ->
{reply, presence_broadcast:current_visible_presence(State), State};
@@ -141,6 +144,12 @@ handle_cast({sync_group_dm_recipients, RecipientsByChannel}, State) when
handle_cast(Msg, State) ->
handle_cast_guild(Msg, State).
-spec session_connect_pid(map(), pid()) -> pid().
session_connect_pid(#{session_pid := Pid}, _CallerPid) when is_pid(Pid) ->
Pid;
session_connect_pid(_Request, CallerPid) ->
CallerPid.
-spec handle_sync_friends_cast([term()], [term()], state()) -> {noreply, state()}.
handle_sync_friends_cast(FriendIds, FlushedIds, State) ->
{noreply,
@@ -280,6 +289,14 @@ normalize_start_link(ignore) ->
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
session_connect_pid_prefers_request_session_pid_test() ->
Caller = self(),
Other = spawn(fun idle_session_proc/0),
?assertEqual(Other, session_connect_pid(#{session_pid => Other}, Caller)),
?assertEqual(Caller, session_connect_pid(#{}, Caller)),
?assertEqual(Caller, session_connect_pid(#{session_pid => undefined}, Caller)),
Other ! stop.
presence_rejoin_notifies_all_sessions_test() ->
Parent = self(),
Session1 = spawn(fun() -> rejoin_check_receiver(Parent, one) end),
@@ -349,6 +366,13 @@ test_session_entry(Pid) ->
socket_pid => undefined
}.
-spec idle_session_proc() -> ok.
idle_session_proc() ->
receive
stop -> ok
after 1000 -> ok
end.
-spec rejoin_check_receiver(pid(), atom()) -> term().
rejoin_check_receiver(Parent, Tag) ->
receive
@@ -414,21 +414,22 @@ handle_resume_offline_timeout(_Msg, State) ->
ok.
notify_presence_on_resume(#{presence_pid := undefined}, _Sid, _St, _Afk, _Mob) ->
ok;
notify_presence_on_resume(#{presence_pid := Pid}, SessionId, Status, Afk, Mobile) ->
spawn(fun() -> notify_presence_on_resume_worker(Pid, SessionId, Status, Afk, Mobile) end),
notify_presence_on_resume(#{presence_pid := Pid} = State, SessionId, Status, Afk, Mobile) ->
Request = #{
session_id => SessionId,
session_pid => self(),
socket_pid => maps:get(socket_pid, State, undefined),
status => Status,
afk => Afk,
mobile => Mobile
},
spawn(fun() -> notify_presence_on_resume_worker(Pid, Request) end),
ok.
-spec notify_presence_on_resume_worker(pid(), session_id(), status(), boolean(), boolean()) ->
ok.
notify_presence_on_resume_worker(Pid, SessionId, Status, Afk, Mobile) ->
-spec notify_presence_on_resume_worker(pid(), map()) -> ok.
notify_presence_on_resume_worker(Pid, Request) ->
try
gen_server:call(
Pid,
{session_connect, #{
session_id => SessionId, status => Status, afk => Afk, mobile => Mobile
}},
10000
),
gen_server:call(Pid, {session_connect, Request}, 10000),
ok
catch
error:_Reason -> ok;
@@ -363,6 +363,31 @@ resume_success_state(State0) ->
{reply, {ok, _Missed, 1}, State1} = session_lifecycle:handle_resume(0, self(), State0),
State1.
handle_resume_registers_the_session_process_with_presence_test() ->
SessionPid = self(),
Presence = spawn(fun() -> fake_presence_loop(SessionPid) end),
State0 = resume_test_state(#{presence_pid => Presence, seq => 1}),
{reply, {ok, [], 1}, _State1} = session_lifecycle:handle_resume(1, self(), State0),
receive
{presence_session_connect, Request} ->
?assertEqual(SessionPid, maps:get(session_pid, Request)),
?assertEqual(<<"session-resume-test">>, maps:get(session_id, Request))
after 2000 ->
?assert(false, presence_session_connect_not_received)
end.
fake_presence_loop(Parent) ->
receive
{'$gen_call', From, {session_connect, Request}} ->
Parent ! {presence_session_connect, Request},
gen_server:reply(From, {ok, []}),
fake_presence_loop(Parent);
_Other ->
fake_presence_loop(Parent)
after 5000 ->
ok
end.
resume_test_state(Overrides) ->
maps:merge(
#{