Packages
livebook
0.16.3
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/proxy/handler.ex
defmodule Livebook.Proxy.Handler do
@moduledoc false
# Handles request `conn` with the configured function.
#
# The handler forwards all actual communication to the parent
# `Livebook.Proxy.Server` via `Livebook.Proxy.Adapter`.
#
# A handler process is started on demand under a task supervisor.
# To avoid bottlenecks, we use a partition supervisor, so that we
# have a group of task supervisors ready.
@name __MODULE__
@doc """
Returns a child spec to setup the handler supervision tree.
Expects the `:listen` option to be provided, and be a function with
the signature `Plug.Conn.t() -> Plug.Conn.t()`.
"""
@spec child_spec(keyword()) :: Supervisor.child_spec()
def child_spec(opts) do
listen = Keyword.fetch!(opts, :listen)
:persistent_term.put({__MODULE__, :listen}, listen)
PartitionSupervisor.child_spec(child_spec: Task.Supervisor, name: @name)
end
@doc """
Handles request with the configured listener function.
Restores `%Plug.Conn{}` from the given attributes and delegates
all response handling back to the parent `Livebook.Proxy.Server`.
"""
@spec serve(pid(), map()) :: Plug.Conn.t()
def serve(parent_pid, %{} = conn_attrs) when is_pid(parent_pid) do
Process.link(parent_pid)
ref = Process.monitor(parent_pid)
conn =
struct!(Plug.Conn, %{conn_attrs | adapter: {Livebook.Proxy.Adapter, {parent_pid, ref}}})
listen = :persistent_term.get({__MODULE__, :listen})
listen.(conn)
end
@doc """
Returns a pid of task supervisor to start the handler under.
In case no supervisor is running, returns `nil`.
"""
@spec get_supervisor_pid() :: pid() | nil
def get_supervisor_pid() do
if Process.whereis(@name) do
key = :rand.uniform()
GenServer.whereis({:via, PartitionSupervisor, {@name, key}})
end
end
end