Do not crash runtime when stopping stopped smart cell (#2314)

This commit is contained in:
Jonatan Kłosko 2023-10-27 21:26:54 +02:00 committed by GitHub
parent 15a7f4eb3f
commit c0e75f64ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 3 deletions

View file

@ -576,6 +576,7 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
put_in(state.smart_cells[ref], info)
{:error, error} ->
send(state.owner, {:runtime_smart_cell_down, ref})
Logger.error("failed to start smart cell - #{Exception.format_exit(error)}")
state
end
@ -594,10 +595,10 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
end
def handle_cast({:stop_smart_cell, ref}, state) do
{%{pid: pid}, state} = pop_in(state.smart_cells[ref])
{info, state} = pop_in(state.smart_cells[ref])
if pid do
DynamicSupervisor.terminate_child(state.smart_cell_supervisor, pid)
if info do
DynamicSupervisor.terminate_child(state.smart_cell_supervisor, info.pid)
end
{:noreply, state}

View file

@ -242,6 +242,10 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServerTest do
@impl true
def init(info) do
if info.attrs["crash"] do
raise "crash"
end
{:ok, info}
end
@ -274,6 +278,13 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServerTest do
assert_receive {:runtime_smart_cell_down, "ref"}
end
@tag opts: @opts
@tag capture_log: true
test "notifies runtime owner when a smart cell fails to start", %{pid: pid} do
RuntimeServer.start_smart_cell(pid, "dumb", "ref", %{"crash" => true}, [])
assert_receive {:runtime_smart_cell_down, "ref"}
end
@tag opts: @opts
test "once started scans binding and sends the result to the cell server", %{pid: pid} do
RuntimeServer.start_smart_cell(pid, "dumb", "ref", %{}, [])
@ -304,5 +315,17 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServerTest do
RuntimeServer.evaluate_code(pid, :elixir, "1 + 1", {:c1, :e1}, [], smart_cell_ref: "ref")
assert_receive {:smart_cell_debug, "ref", :handle_info, :scan_eval_result_ping}
end
@tag opts: @opts
test "ignores stop request for stopped smart cells", %{pid: pid} do
RuntimeServer.start_smart_cell(pid, "dumb", "ref", %{}, [])
assert_receive {:runtime_smart_cell_started, "ref", %{js_view: %{pid: smart_cell_pid}}}
Process.exit(smart_cell_pid, :crashed)
assert_receive {:runtime_smart_cell_down, "ref"}
RuntimeServer.stop_smart_cell(pid, "ref")
# The server should still be operational
RuntimeServer.evaluate_code(pid, :elixir, "1 + 1", {:c1, :e1}, [])
end
end
end