diff --git a/apps/els_core/src/els_distribution_server.erl b/apps/els_core/src/els_distribution_server.erl index 68ef6456a..2ad857bcb 100644 --- a/apps/els_core/src/els_distribution_server.erl +++ b/apps/els_core/src/els_distribution_server.erl @@ -134,13 +134,19 @@ handle_info(Request, State) -> %%============================================================================== -spec connect_and_monitor(atom()) -> ok | error. connect_and_monitor(Node) -> - case net_kernel:connect_node(Node) of + case lists:member(Node, erlang:nodes(connected)) of true -> - ?LOG_INFO("Connected to node [node=~p]", [Node]), - erlang:monitor_node(Node, true), + ?LOG_DEBUG("Already connected to node [node=~p]", [Node]), ok; false -> - error + case net_kernel:connect_node(Node) of + true -> + ?LOG_INFO("Connected to node [node=~p]", [Node]), + erlang:monitor_node(Node, true), + ok; + false -> + error + end end. -spec start(atom()) -> ok. @@ -170,7 +176,7 @@ wait_connect_and_monitor(Node, Attempts) -> ok -> ok; error -> - ?LOG_WARNING( "Trying to connect to node ~p (~p/~p)" + ?LOG_DEBUG( "Trying to connect to node ~p (~p/~p)" , [Node, ?WAIT_ATTEMPTS - Attempts + 1, ?WAIT_ATTEMPTS]), wait_connect_and_monitor(Node, Attempts - 1) end. diff --git a/apps/els_dap/src/els_dap_general_provider.erl b/apps/els_dap/src/els_dap_general_provider.erl index 5873a964b..19b7df79d 100644 --- a/apps/els_dap/src/els_dap_general_provider.erl +++ b/apps/els_dap/src/els_dap_general_provider.erl @@ -158,10 +158,8 @@ handle_request( {<<"setBreakpoints">>, Params} SourceBreakpoints = maps:get(<<"breakpoints">>, Params, []), _SourceModified = maps:get(<<"sourceModified">>, Params, false), Module = els_uri:module(els_uri:uri(Path)), - els_distribution_server:wait_connect_and_monitor(ProjectNode), - {module, Module} = els_dap_rpc:i(ProjectNode, Module), Lines = [Line || #{<<"line">> := Line} <- SourceBreakpoints], @@ -377,7 +375,7 @@ handle_request({<<"disconnect">>, _Params}, State) -> els_utils:halt(0), {#{}, State}. --spec handle_info(any(), state()) -> state(). +-spec handle_info(any(), state()) -> state() | no_return(). handle_info( {int_cb, ThreadPid} , #{ threads := Threads , project_node := ProjectNode @@ -391,7 +389,15 @@ handle_info( {int_cb, ThreadPid} els_dap_server:send_event(<<"stopped">>, #{ <<"reason">> => <<"breakpoint">> , <<"threadId">> => ThreadId }), - State#{threads => maps:put(ThreadId, Thread, Threads)}. + State#{threads => maps:put(ThreadId, Thread, Threads)}; +handle_info({nodedown, Node}, State) -> + %% the project node is down, there is nothing left to do then to exit + ?LOG_NOTICE("project node ~p terminated, ending debug session", [Node]), + els_dap_server:send_event(<<"terminated">>, #{}), + els_dap_server:send_event(<<"exited">>, #{ <<"exitCode">> => <<"0">>}), + ?LOG_NOTICE("terminating debug adapter"), + els_utils:halt(0), + State. %%============================================================================== %% API diff --git a/apps/els_dap/test/els_dap_general_provider_SUITE.erl b/apps/els_dap/test/els_dap_general_provider_SUITE.erl index b7c26756b..26179721e 100644 --- a/apps/els_dap/test/els_dap_general_provider_SUITE.erl +++ b/apps/els_dap/test/els_dap_general_provider_SUITE.erl @@ -20,7 +20,8 @@ frame_variables/1, navigation_and_frames/1, set_variable/1, - breakpoints/1 + breakpoints/1, + project_node_exit/1 ]). %% TODO: cleanup after dropping support for OTP 21 and 22 @@ -65,6 +66,7 @@ init_per_testcase(TestCase, Config) when TestCase =:= undefined orelse TestCase =:= initialize orelse TestCase =:= launch_mfa orelse + TestCase =:= launch_mfa_with_cookie orelse TestCase =:= configuration_done orelse TestCase =:= configuration_done_with_breakpoint -> @@ -391,6 +393,23 @@ breakpoints(Config) -> ?assertMatch([{{els_dap_test_module, 9}, _}], els_dap_rpc:all_breaks(Node)), ok. +-spec project_node_exit(config()) -> ok. +project_node_exit(Config) -> + NodeName = ?config(node, Config), + Node = binary_to_atom(NodeName), + meck:expect(els_utils, halt, 1, meck:val(ok)), + meck:reset(els_dap_server), + erlang:monitor_node(Node, true), + %% kill node and wait for nodedown message + rpc:cast(Node, erlang, halt, []), + receive + {nodedown, Node} -> ok + end, + %% wait until els_utils:halt has been called + els_dap_test_utils:wait_until_mock_called(els_utils, halt), + ?assert(meck:called(els_dap_server, send_event, [<<"terminated">>, '_'])), + ?assert(meck:called(els_dap_server, send_event, [<<"exited">>, '_'])). + %%============================================================================== %% Requests %%==============================================================================