Skip to content

Commit fd795cd

Browse files
committed
do not respond to cancelled requests
demonitor requests on response/cancel optimize DOWN message handling
1 parent a927fde commit fd795cd

File tree

1 file changed

+117
-72
lines changed
  • apps/elixir_ls_debugger/lib/debugger

1 file changed

+117
-72
lines changed

apps/elixir_ls_debugger/lib/debugger/server.ex

Lines changed: 117 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ defmodule ElixirLS.Debugger.Server do
4848
}
4949
},
5050
requests: %{},
51+
requests_seqs_by_pid: %{},
5152
progresses: MapSet.new(),
5253
next_id: 1,
5354
output: Output,
@@ -314,40 +315,61 @@ defmodule ElixirLS.Debugger.Server do
314315
_from,
315316
state = %__MODULE__{}
316317
) do
317-
if MapSet.member?(state.progresses, packet["seq"]) do
318-
Output.send_event("progressEnd", %{
319-
"progressId" => packet["seq"]
320-
})
321-
end
318+
seq = packet["seq"]
319+
{request, updated_requests} = Map.pop(state.requests, seq)
322320

323-
case result do
324-
{:error, e = %ServerError{}} ->
325-
Output.send_error_response(
326-
packet,
327-
e.message,
328-
e.format,
329-
e.variables,
330-
e.send_telemetry,
331-
e.show_user
332-
)
321+
{updated_requests_seqs_by_pid, updated_progresses} =
322+
if request do
323+
{pid, ref, _packet} = request
333324

334-
{:ok, response_body} ->
335-
elapsed = System.monotonic_time(:millisecond) - start_time
336-
Output.send_response(packet, response_body)
325+
# we are not interested in :DOWN message anymore
326+
Process.demonitor(ref, [:flush])
337327

338-
Output.telemetry(
339-
"dap_request",
340-
%{"elixir_ls.dap_command" => String.replace(command, "/", "_")},
341-
%{
342-
"elixir_ls.dap_request_time" => elapsed
343-
}
344-
)
345-
end
328+
updated_progresses =
329+
if MapSet.member?(state.progresses, seq) do
330+
Output.send_event("progressEnd", %{
331+
"progressId" => seq
332+
})
333+
334+
MapSet.delete(state.progresses, seq)
335+
else
336+
state.progresses
337+
end
338+
339+
case result do
340+
{:error, e = %ServerError{}} ->
341+
Output.send_error_response(
342+
packet,
343+
e.message,
344+
e.format,
345+
e.variables,
346+
e.send_telemetry,
347+
e.show_user
348+
)
349+
350+
{:ok, response_body} ->
351+
elapsed = System.monotonic_time(:millisecond) - start_time
352+
Output.send_response(packet, response_body)
353+
354+
Output.telemetry(
355+
"dap_request",
356+
%{"elixir_ls.dap_command" => String.replace(command, "/", "_")},
357+
%{
358+
"elixir_ls.dap_request_time" => elapsed
359+
}
360+
)
361+
end
362+
363+
{Map.delete(state.requests_seqs_by_pid, pid), updated_progresses}
364+
else
365+
{state.requests_seqs_by_pid, state.progresses}
366+
end
346367

347368
state = %{
348369
state
349-
| requests: Map.delete(state.requests, packet["seq"]),
350-
progresses: MapSet.delete(state.progresses, packet["seq"])
370+
| requests: updated_requests,
371+
requests_seqs_by_pid: updated_requests_seqs_by_pid,
372+
progresses: updated_progresses
351373
}
352374

353375
{:reply, :ok, state}
@@ -421,8 +443,13 @@ defmodule ElixirLS.Debugger.Server do
421443
state
422444

423445
{:async, fun, state} ->
424-
{pid, _ref} = handle_request_async(packet, start_time, fun)
425-
%{state | requests: Map.put(state.requests, seq, {pid, packet})}
446+
{pid, ref} = handle_request_async(packet, start_time, fun)
447+
448+
%{
449+
state
450+
| requests: Map.put(state.requests, seq, {pid, ref, packet}),
451+
requests_seqs_by_pid: Map.put(state.requests_seqs_by_pid, pid, seq)
452+
}
426453
end
427454

428455
{:noreply, state}
@@ -525,38 +552,45 @@ defmodule ElixirLS.Debugger.Server do
525552

526553
# if the exited process was a request handler respond with error
527554
# and optionally end progress
528-
request =
529-
state.requests
530-
|> Enum.find(fn {_request_id, {request_pid, _packet}} -> request_pid == pid end)
555+
{seq, updated_requests_seqs_by_pid} = Map.pop(state.requests_seqs_by_pid, pid)
531556

532-
state =
533-
case request do
534-
{request_id, {_pid, packet}} ->
535-
Output.send_error_response(
536-
packet,
537-
"internalServerError",
538-
"Request handler exited with reason #{Exception.format_exit(reason)}",
539-
%{},
540-
true,
541-
false
542-
)
557+
{updated_requests, updated_progresses} =
558+
if seq do
559+
{{_pid, _ref, packet}, updated_requests} = Map.pop!(state.requests, seq)
560+
561+
Output.send_error_response(
562+
packet,
563+
"internalServerError",
564+
"Request handler exited with reason #{Exception.format_exit(reason)}",
565+
%{},
566+
true,
567+
false
568+
)
543569

544-
if MapSet.member?(state.progresses, request_id) do
570+
# no MapSet.pop...
571+
updated_progresses =
572+
if MapSet.member?(state.progresses, seq) do
545573
Output.send_event("progressEnd", %{
546-
"progressId" => request_id
574+
"progressId" => seq
547575
})
548-
end
549576

550-
%{
551-
state
552-
| requests: Map.delete(state.requests, request_id),
553-
progresses: MapSet.delete(state.progresses, request_id)
554-
}
577+
MapSet.delete(state.progresses, seq)
578+
else
579+
state.progresses
580+
end
555581

556-
nil ->
557-
state
582+
{updated_requests, updated_progresses}
583+
else
584+
{state.requests, state.progresses}
558585
end
559586

587+
state = %{
588+
state
589+
| requests: updated_requests,
590+
requests_seqs_by_pid: updated_requests_seqs_by_pid,
591+
progresses: updated_progresses
592+
}
593+
560594
{:noreply, state}
561595
end
562596

@@ -627,34 +661,45 @@ defmodule ElixirLS.Debugger.Server do
627661
# in or case progressId is requestId so choose first not null
628662
request_or_progress_id = args["requestId"] || args["progressId"]
629663

630-
state =
631-
case requests do
632-
%{^request_or_progress_id => {pid, packet}} ->
633-
Process.exit(pid, :cancelled)
634-
Output.send_error_response(packet, "cancelled", "cancelled", %{}, false, false)
664+
{request, updated_requests} = Map.pop(requests, request_or_progress_id)
665+
666+
{updated_requests_seqs_by_pid, updated_progresses} =
667+
if request do
668+
{pid, ref, packet} = request
669+
# flush as we are not interested in :DOWN message anymore
670+
Process.demonitor(ref, [:flush])
671+
Process.exit(pid, :cancelled)
672+
Output.send_error_response(packet, "cancelled", "cancelled", %{}, false, false)
635673

636-
# send progressEnd if cancelling a progress
674+
# send progressEnd if cancelling a progress
675+
updated_progresses =
637676
if MapSet.member?(state.progresses, request_or_progress_id) do
638677
Output.send_event("progressEnd", %{
639678
"progressId" => request_or_progress_id
640679
})
680+
681+
MapSet.delete(state.progresses, request_or_progress_id)
682+
else
683+
state.progresses
641684
end
642685

643-
%{
644-
state
645-
| requests: Map.delete(requests, request_or_progress_id),
646-
progresses: MapSet.delete(state.progresses, request_or_progress_id)
686+
{Map.delete(state.requests_seqs_by_pid, pid), updated_progresses}
687+
else
688+
raise ServerError,
689+
message: "invalidRequest",
690+
format: "Request or progress {reguestOrProgressId} cannot be cancelled",
691+
variables: %{
692+
"reguestOrProgressId" => inspect(request_or_progress_id)
647693
}
648-
649-
_ ->
650-
raise ServerError,
651-
message: "invalidRequest",
652-
format: "Request or progress {reguestOrProgressId} cannot be cancelled",
653-
variables: %{
654-
"reguestOrProgressId" => inspect(request_or_progress_id)
655-
}
656694
end
657695

696+
state = %{
697+
state
698+
| requests: updated_requests,
699+
requests_seqs_by_pid: updated_requests_seqs_by_pid,
700+
progresses: updated_progresses
701+
}
702+
658703
{%{}, state}
659704
end
660705

0 commit comments

Comments
 (0)