Skip to content

Commit

Permalink
Fix WS disconnection handling
Browse files Browse the repository at this point in the history
- Demonitor the gun process before shutting it down through gun.
- Handle disconnections detected by monitor ('DOWN' monitor message)
  • Loading branch information
ziopio committed May 22, 2024
1 parent f9f40f7 commit e60b25b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 8 deletions.
9 changes: 7 additions & 2 deletions src/grisp_connect_ws.erl
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,17 @@ handle_info({gun_down, Pid, ws, closed, [Stream]}, #state{gun_pid = Pid, ws_stre
?LOG_WARNING(#{event => ws_closed}),
grisp_connect_client:disconnected(),
{noreply, shutdown_gun(S)};
handle_info({'DOWN', _, process, Pid, Reason}, #state{gun_pid = Pid} = S) ->
?LOG_WARNING(#{event => gun_crash, reason => Reason}),
grisp_connect_client:disconnected(),
{noreply, S?disconnected_state};
handle_info(M, S) ->
?LOG_WARNING(#{event => unhandled_info, info => M}),
?LOG_WARNING(#{event => unhandled_info, info => M, state => S}),
{noreply, S}.

% internal functions -----------------------------------------------------------

shutdown_gun(#state{gun_pid = Pid} = State) ->
shutdown_gun(#state{gun_pid = Pid, gun_ref = GunRef} = State) ->
demonitor(GunRef),
gun:shutdown(Pid),
State?disconnected_state.
16 changes: 16 additions & 0 deletions test/grisp_connect_api_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
-compile([export_all, nowarn_export_all]).

-import(grisp_connect_test_client, [wait_connection/0]).
-import(grisp_connect_test_client, [wait_connection/1]).
-import(grisp_connect_test_client, [wait_disconnection/0]).
-import(grisp_connect_test_client, [serial_number/0]).
-import(grisp_connect_test_client, [cert_dir/0]).

Expand Down Expand Up @@ -69,6 +71,20 @@ link_device_test(_) ->
?assertMatch({ok, <<"ok">>}, grisp_connect:link_device()),
?assertMatch({ok, <<"pong">>}, grisp_connect:ping()).

reconnect_on_gun_crash_test(_) ->
{state, GunPid, _, _, _} = sys:get_state(grisp_connect_ws),
proc_lib:stop(GunPid),
?assertMatch(ok, wait_disconnection()),
?assertMatch(ok, wait_connection()).

reconnect_on_disconnection_test(Config) ->
KraftRef = ?config(kraft_instance, Config),
kraft:stop(KraftRef),
?assertMatch(ok, wait_disconnection()),
KraftRef2 = grisp_connect_manager:kraft_start(cert_dir()),
?assertMatch(ok, wait_connection(100)),
[{kraft_instance, KraftRef2} | proplists:delete(kraft_instance, Config)].

%--- Internal ------------------------------------------------------------------

flush() ->
Expand Down
11 changes: 7 additions & 4 deletions test/grisp_connect_manager.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ start(CertDir, Config) ->
application:start(mnesia),

{ok, Started2} = application:ensure_all_started(kraft),
KraftRef = kraft_start(CertDir),

{ok, Started3} = application:ensure_all_started(grisp_manager),
[{apps, Started1 ++ Started2 ++ Started3}, {kraft_instance , KraftRef} | Config].

kraft_start(CertDir) ->
SslOpts = [
{verify, verify_peer},
{keyfile, filename:join(CertDir, "server.key")},
Expand All @@ -33,10 +39,7 @@ start(CertDir, Config) ->
{"/grisp-connect/ws",
{ws, grisp_manager_device_api}, #{}, #{type => json_rpc}}
],
kraft:start(KraftOpts, KraftRoutes),

{ok, Started3} = application:ensure_all_started(grisp_manager),
[{apps, Started1 ++ Started2 ++ Started3} | Config].
kraft:start(KraftOpts, KraftRoutes).

cleanup_apps(Apps) ->
mnesia:delete_table(eresu_user),
Expand Down
20 changes: 18 additions & 2 deletions test/grisp_connect_test_client.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
-export([cert_dir/0]).
-export([serial_number/0]).
-export([wait_connection/0]).
-export([wait_connection/1]).
-export([wait_disconnection/0]).

%--- API -----------------------------------------------------------------------

cert_dir() -> filename:join(code:lib_dir(grisp_connect, test), "certs").
cert_dir() -> filename:join(code:lib_dir(grisp_connect, test), "certs").

serial_number() -> <<"0000">>.

wait_connection() ->
wait_connection(20).

wait_connection(0) ->
ct:pal("grisp_connect state:~n~p~n", [sys:get_state(grisp_connect_client)]),
ct:pal("grisp_connect_ws state:~n~p~n", [sys:get_state(grisp_connect_ws)]),
{error, timeout};
wait_connection(N) ->
case grisp_connect:is_connected() of
Expand All @@ -26,3 +28,17 @@ wait_connection(N) ->
ct:sleep(100),
wait_connection(N - 1)
end.

wait_disconnection() ->
wait_disconnection(20).

wait_disconnection(0) ->
ct:pal("grisp_connect_ws state:~n~p~n", [sys:get_state(grisp_connect_ws)]),
{error, timeout};
wait_disconnection(N) ->
case grisp_connect:is_connected() of
true ->
ct:sleep(100),
wait_disconnection(N - 1);
false -> ok
end.

0 comments on commit e60b25b

Please sign in to comment.