From ccf34ba8947880d5b13a5ec562490a576f261c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Sun, 22 Oct 2023 20:28:55 +0200 Subject: [PATCH] Do not redeploy apps from dir on every node (#2291) --- lib/livebook/application.ex | 3 ++- lib/livebook/apps.ex | 39 +++++++++++++++++++++++++------------ test/livebook/apps_test.exs | 24 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/lib/livebook/application.ex b/lib/livebook/application.ex index 7737d441dcb..7143c879b48 100644 --- a/lib/livebook/application.ex +++ b/lib/livebook/application.ex @@ -333,7 +333,8 @@ defmodule Livebook.Application do Livebook.Apps.deploy_apps_in_dir(apps_path, password: Livebook.Config.apps_path_password(), - warmup: warmup + warmup: warmup, + start_only: true ) end end diff --git a/lib/livebook/apps.ex b/lib/livebook/apps.ex index 7a0f84236ab..588a215bdf8 100644 --- a/lib/livebook/apps.ex +++ b/lib/livebook/apps.ex @@ -22,10 +22,14 @@ defmodule Livebook.Apps do * `:files_source` - a location to fetch notebook files from, see `Livebook.Session.start_link/1` for more details + * `:start_only` - when `true`, deploys only if the app does not + exist already. Defaults to `false` + """ - @spec deploy(Livebook.Notebook.t(), keyword()) :: {:ok, pid()} | {:error, term()} + @spec deploy(Livebook.Notebook.t(), keyword()) :: + {:ok, pid()} | {:error, :already_started} | {:error, term()} def deploy(notebook, opts \\ []) do - opts = Keyword.validate!(opts, warnings: [], files_source: nil) + opts = Keyword.validate!(opts, warnings: [], files_source: nil, start_only: false) slug = notebook.app_settings.slug name = name(slug) @@ -41,18 +45,12 @@ defmodule Livebook.Apps do end pid -> - App.deploy(pid, notebook, - warnings: opts[:warnings], - files_source: opts[:files_source] - ) - - {:ok, pid} + redeploy_app(pid, notebook, opts) end end) pid -> - App.deploy(pid, notebook, warnings: opts[:warnings], files_source: opts[:files_source]) - {:ok, pid} + redeploy_app(pid, notebook, opts) end end @@ -77,6 +75,15 @@ defmodule Livebook.Apps do end end + defp redeploy_app(pid, notebook, opts) do + if opts[:start_only] do + {:error, :already_started} + else + App.deploy(pid, notebook, warnings: opts[:warnings], files_source: opts[:files_source]) + {:ok, pid} + end + end + @doc """ Returns app process pid for the given slug. """ @@ -166,10 +173,14 @@ defmodule Livebook.Apps do This can be used to warmup apps without deployment. Defaults to `false` + * `:start_only` - when `true`, deploys only if the app does not + exist already. Defaults to `false` + """ @spec deploy_apps_in_dir(String.t(), keyword()) :: :ok def deploy_apps_in_dir(path, opts \\ []) do - opts = Keyword.validate!(opts, [:password, warmup: true, skip_deploy: false]) + opts = + Keyword.validate!(opts, [:password, warmup: true, skip_deploy: false, start_only: false]) infos = import_app_notebooks(path) @@ -226,7 +237,11 @@ defmodule Livebook.Apps do warnings = Enum.map(info.import_warnings, &("Import: " <> &1)) - {:ok, _} = deploy(notebook, warnings: warnings, files_source: info.files_source) + deploy(notebook, + warnings: warnings, + files_source: info.files_source, + start_only: opts[:start_only] + ) end end diff --git a/test/livebook/apps_test.exs b/test/livebook/apps_test.exs index 021fa5f015a..b8a8e5aa168 100644 --- a/test/livebook/apps_test.exs +++ b/test/livebook/apps_test.exs @@ -261,5 +261,29 @@ defmodule Livebook.AppsTest do Livebook.App.close(app.pid) end + + @tag :tmp_dir + test "skips existing apps when :start_only is enabled", %{tmp_dir: tmp_dir} do + app_path = Path.join(tmp_dir, "app.livemd") + + File.write!(app_path, """ + + + # App + """) + + Livebook.Apps.subscribe() + + Livebook.Apps.deploy_apps_in_dir(tmp_dir) + assert_receive {:app_updated, app} + + Livebook.Apps.deploy_apps_in_dir(tmp_dir) + assert %{version: 2} = Livebook.App.get_by_pid(app.pid) + + Livebook.Apps.deploy_apps_in_dir(tmp_dir, start_only: true) + assert %{version: 2} = Livebook.App.get_by_pid(app.pid) + + Livebook.App.close(app.pid) + end end end