mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-09-08 14:04:31 +08:00
Save notebook and notify clients when session is stopped (#45)
This commit is contained in:
parent
0925ec77cd
commit
c1eafc9a2c
5 changed files with 47 additions and 6 deletions
|
@ -215,11 +215,14 @@ defmodule LiveBook.Session do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Synchronously stops the server.
|
Asynchronously sends a close request to the server.
|
||||||
|
|
||||||
|
This results in saving the file and broadcasting
|
||||||
|
a :closed message to the session topic.
|
||||||
"""
|
"""
|
||||||
@spec stop(id()) :: :ok
|
@spec close(id()) :: :ok
|
||||||
def stop(session_id) do
|
def close(session_id) do
|
||||||
GenServer.stop(name(session_id))
|
GenServer.cast(name(session_id), :close)
|
||||||
end
|
end
|
||||||
|
|
||||||
## Callbacks
|
## Callbacks
|
||||||
|
@ -377,6 +380,13 @@ defmodule LiveBook.Session do
|
||||||
{:noreply, maybe_save_notebook(state)}
|
{:noreply, maybe_save_notebook(state)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_cast(:close, state) do
|
||||||
|
maybe_save_notebook(state)
|
||||||
|
broadcast_message(state.session_id, :session_closed)
|
||||||
|
|
||||||
|
{:stop, :shutdown, state}
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:DOWN, ref, :process, _, _}, %{runtime_monitor_ref: ref} = state) do
|
def handle_info({:DOWN, ref, :process, _, _}, %{runtime_monitor_ref: ref} = state) do
|
||||||
broadcast_info(state.session_id, "runtime node terminated unexpectedly")
|
broadcast_info(state.session_id, "runtime node terminated unexpectedly")
|
||||||
|
|
|
@ -50,13 +50,13 @@ defmodule LiveBook.SessionSupervisor do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Synchronously stops a session process identified by the given id.
|
Asynchronously stops a session process identified by the given id.
|
||||||
|
|
||||||
Broadcasts `{:session_delete, id}` message under the `"sessions"` topic.
|
Broadcasts `{:session_delete, id}` message under the `"sessions"` topic.
|
||||||
"""
|
"""
|
||||||
@spec delete_session(Session.id()) :: :ok
|
@spec delete_session(Session.id()) :: :ok
|
||||||
def delete_session(id) do
|
def delete_session(id) do
|
||||||
Session.stop(id)
|
Session.close(id)
|
||||||
broadcast_sessions_message({:session_deleted, id})
|
broadcast_sessions_message({:session_deleted, id})
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
|
@ -382,6 +382,13 @@ defmodule LiveBookWeb.SessionLive do
|
||||||
{:noreply, put_flash(socket, :info, message)}
|
{:noreply, put_flash(socket, :info, message)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_info(:session_closed, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(:info, "Session has been closed")
|
||||||
|
|> push_redirect(to: Routes.home_path(socket, :page))}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_info(_message, socket), do: {:noreply, socket}
|
def handle_info(_message, socket), do: {:noreply, socket}
|
||||||
|
|
||||||
defp after_operation(socket, _prev_socket, {:insert_section, _index, section_id}) do
|
defp after_operation(socket, _prev_socket, {:insert_section, _index, section_id}) do
|
||||||
|
|
|
@ -23,9 +23,11 @@ defmodule LiveBook.SessionSupervisorTest do
|
||||||
test "stops the session process identified by the given id" do
|
test "stops the session process identified by the given id" do
|
||||||
{:ok, id} = SessionSupervisor.create_session()
|
{:ok, id} = SessionSupervisor.create_session()
|
||||||
{:ok, pid} = SessionSupervisor.get_session_pid(id)
|
{:ok, pid} = SessionSupervisor.get_session_pid(id)
|
||||||
|
ref = Process.monitor(pid)
|
||||||
|
|
||||||
SessionSupervisor.delete_session(id)
|
SessionSupervisor.delete_session(id)
|
||||||
|
|
||||||
|
assert_receive {:DOWN, ^ref, :process, _, _}
|
||||||
refute has_child_with_pid?(SessionSupervisor, pid)
|
refute has_child_with_pid?(SessionSupervisor, pid)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,28 @@ defmodule LiveBook.SessionTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "close/1" do
|
||||||
|
@tag :tmp_dir
|
||||||
|
test "saves the notebook and notifies subscribers once the session is closed",
|
||||||
|
%{session_id: session_id, tmp_dir: tmp_dir} do
|
||||||
|
path = Path.join(tmp_dir, "notebook.livemd")
|
||||||
|
Session.set_path(session_id, path)
|
||||||
|
# Perform a change, so the notebook is dirty
|
||||||
|
Session.set_notebook_name(session_id, "My notebook")
|
||||||
|
|
||||||
|
Phoenix.PubSub.subscribe(LiveBook.PubSub, "sessions:#{session_id}")
|
||||||
|
|
||||||
|
refute File.exists?(path)
|
||||||
|
|
||||||
|
Process.flag(:trap_exit, true)
|
||||||
|
Session.close(session_id)
|
||||||
|
|
||||||
|
assert_receive :session_closed
|
||||||
|
assert File.exists?(path)
|
||||||
|
assert File.read!(path) =~ "My notebook"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "start_link/1" do
|
describe "start_link/1" do
|
||||||
@tag :tmp_dir
|
@tag :tmp_dir
|
||||||
test "fails if the given path is already in use", %{tmp_dir: tmp_dir} do
|
test "fails if the given path is already in use", %{tmp_dir: tmp_dir} do
|
||||||
|
|
Loading…
Add table
Reference in a new issue