Packages
livebook
0.12.0
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/utils/unique_task.ex
defmodule Livebook.Utils.UniqueTask.Task do
use GenServer, restart: :temporary
@registry Livebook.Utils.UniqueTask.Registry
def start_link({key, fun}) do
GenServer.start_link(__MODULE__, fun, name: {:via, Registry, {@registry, key}})
end
@impl true
def init(fun) do
{:ok, nil, {:continue, fun}}
end
@impl true
def handle_continue(fun, state) do
fun.()
{:stop, :shutdown, state}
end
end
defmodule Livebook.Utils.UniqueTask do
use Supervisor
@registry Livebook.Utils.UniqueTask.Registry
@supervisor Livebook.Utils.UniqueTask.Supervisor
@task Livebook.Utils.UniqueTask.Task
def start_link(_opts) do
Supervisor.start_link(__MODULE__, {}, name: __MODULE__)
end
@impl true
def init({}) do
children = [
{Registry, name: @registry, keys: :unique},
{DynamicSupervisor, name: @supervisor, strategy: :one_for_one}
]
Supervisor.init(children, strategy: :one_for_all)
end
@doc """
Runs the given function in a separate process, unless the key is
already taken.
If another function is already running under the given key, this
call only waits for it to finish and then returns the same status.
Returns `:ok` if function finishes successfully and `:error` if it
crashes.
"""
@spec run(term(), function()) :: :ok | :error
def run(key, fun) do
pid =
case Registry.lookup(@registry, key) do
[{pid, _}] ->
pid
[] ->
case DynamicSupervisor.start_child(@supervisor, {@task, {key, fun}}) do
{:ok, pid} -> pid
{:error, {:already_started, pid}} -> pid
end
end
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, reason} ->
case reason do
:normal -> :ok
:shutdown -> :ok
{:shutdown, _} -> :ok
:noproc -> :ok
_ -> :error
end
end
end
end