From bd51878b41581a4d4239ac1e37c4aed943a04b33 Mon Sep 17 00:00:00 2001 From: Connor Rigby Date: Mon, 18 Nov 2019 13:24:06 -0800 Subject: [PATCH] Force bootupsequence worker to check farmware before executing --- .../farmware_installation_worker.ex | 27 +++++++++--- farmbot_core/mix.exs | 2 +- farmbot_os/config/target/dev.exs | 4 ++ farmbot_os/config/target/prod.exs | 4 ++ .../lib/farmbot_os/bootup_sequence_worker.ex | 43 ++++++++++++++++--- farmbot_os/mix.exs | 2 +- 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/farmbot_core/lib/farmbot_core/asset_workers/farmware_installation_worker.ex b/farmbot_core/lib/farmbot_core/asset_workers/farmware_installation_worker.ex index 3954c2d8..a38ffd13 100644 --- a/farmbot_core/lib/farmbot_core/asset_workers/farmware_installation_worker.ex +++ b/farmbot_core/lib/farmbot_core/asset_workers/farmware_installation_worker.ex @@ -22,7 +22,8 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do def init(fwi) do :ok = DepTracker.register_asset(fwi, :init) - {:ok, %{fwi: fwi, backoff: 0}, 0} + send self(), :timeout + {:ok, %{fwi: fwi, backoff: 0}} end def handle_cast(:update, state) do @@ -49,8 +50,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do error -> backoff = state.backoff + @back_off_time_ms timeout = @error_retry_time_ms + backoff + Process.send_after(self(), :timeout, timeout) error_log(fwi, "Failed to download Farmware manifest. Trying again in #{timeout}ms #{inspect(error)}") - {:noreply, %{state | backoff: backoff}, timeout} + {:noreply, %{state | backoff: backoff}} end end @@ -78,16 +80,17 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do updated = FWI.changeset(fwi, %{manifest: nil, updated_at: fwi.updated_at}) |> Repo.update!() - - {:noreply, %{state | fwi: updated}, 0} + send self(), :timeout + {:noreply, %{state | fwi: updated}} error -> :ok = DepTracker.register_asset(fwi, :complete) BotState.report_farmware_installed(fwi.manifest.package, Manifest.view(fwi.manifest)) backoff = state.backoff + @back_off_time_ms timeout = @error_retry_time_ms + backoff + Process.send_after(self(), :timeout, timeout) error_log(fwi, "failed to check for updates. Trying again in #{timeout}ms #{inspect(error)}") - {:noreply, %{state | backoff: backoff}, timeout} + {:noreply, %{state | backoff: backoff}} end end @@ -125,8 +128,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do er -> backoff = state.backoff + @back_off_time_ms timeout = @error_retry_time_ms + backoff + Process.send_after(self(), :timeout, timeout) error_log(updated, "update failed. Trying again in #{timeout}ms #{inspect(er)}") - {:noreply, %{state | fwi: updated, backoff: backoff}, timeout} + {:noreply, %{state | fwi: updated, backoff: backoff}} end end end @@ -253,7 +257,16 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do end defp httpc_options, do: [body_format: :binary] - defp httpc_headers, do: [{'user-agent', 'farmbot-os'}] + + case System.get_env("GITHUB_TOKEN") do + nil -> + defp httpc_headers, do: [{'user-agent', 'farmbot-farmware-installer'}] + + token when is_binary(token) -> + @token token + require Logger; Logger.info "using github token: #{@token}" + defp httpc_headers, do: [{'user-agent', 'farmbot-farmware-installer'}, {'Authorization', 'token #{@token}'}] + end def install_dir(%FWI{} = fwi) do install_dir(fwi.manifest) diff --git a/farmbot_core/mix.exs b/farmbot_core/mix.exs index b261db01..78f98bea 100644 --- a/farmbot_core/mix.exs +++ b/farmbot_core/mix.exs @@ -51,7 +51,7 @@ defmodule FarmbotCore.MixProject do # Run "mix help compile.app" to learn about applications. def application do [ - extra_applications: [:logger], + extra_applications: [:logger, :inets], mod: {FarmbotCore, []} ] end diff --git a/farmbot_os/config/target/dev.exs b/farmbot_os/config/target/dev.exs index 42fd3243..35db7680 100644 --- a/farmbot_os/config/target/dev.exs +++ b/farmbot_os/config/target/dev.exs @@ -92,6 +92,10 @@ config :farmbot_core, FarmbotCore.Asset.Repo, config :farmbot_telemetry, file: to_charlist(Path.join(data_path, 'farmbot-telemetry.dets')) +config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation, + error_retry_time_ms: 30_000, + install_dir: Path.join(data_path, "farmware") + config :farmbot, FarmbotOS.Platform.Supervisor, platform_children: [ FarmbotOS.Platform.Target.NervesHubClient, diff --git a/farmbot_os/config/target/prod.exs b/farmbot_os/config/target/prod.exs index ea33bbe7..0f96f731 100644 --- a/farmbot_os/config/target/prod.exs +++ b/farmbot_os/config/target/prod.exs @@ -92,6 +92,10 @@ config :farmbot_core, FarmbotCore.Asset.Repo, config :farmbot_telemetry, file: to_charlist(Path.join(data_path, 'farmbot-telemetry.dets')) +config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation, + error_retry_time_ms: 30_000, + install_dir: Path.join(data_path, "farmware") + config :farmbot, FarmbotOS.Platform.Supervisor, platform_children: [ FarmbotOS.Platform.Target.NervesHubClient, diff --git a/farmbot_os/lib/farmbot_os/bootup_sequence_worker.ex b/farmbot_os/lib/farmbot_os/bootup_sequence_worker.ex index 4a8f5081..91975386 100644 --- a/farmbot_os/lib/farmbot_os/bootup_sequence_worker.ex +++ b/farmbot_os/lib/farmbot_os/bootup_sequence_worker.ex @@ -16,6 +16,9 @@ defmodule FarmbotOS.BootupSequenceWorker do end def init(_args) do + # all_required_farmwares = + # FarmbotCore.Asset.Repo.all(FarmbotCore.Asset.FirstPartyFarmware) ++ + # FarmbotCore.Asset.Repo.all(FarmbotCore.Asset.FarmwareInstallation) %{ informational_settings: %{ sync_status: sync_status, @@ -30,6 +33,7 @@ defmodule FarmbotOS.BootupSequenceWorker do firmware_idle: fw_idle, firmware_version: fw_version, firmware_configured: fw_configured, + farmwares_loaded: false, sequence_id: nil, sequence_started_at: nil, sequence_completed_at: nil, @@ -41,10 +45,13 @@ defmodule FarmbotOS.BootupSequenceWorker do end def handle_info(:checkup, state) do + Logger.debug("| bootup sequence | checkup ok") {:noreply, maybe_start_sequence(state)} end def handle_info(:start_sequence, %{sequence_id: id} = state) do + Logger.debug("| bootup sequence | start_sequence begin") + case Asset.get_sequence(id) do nil -> FarmbotCore.Logger.error(1, """ @@ -55,10 +62,12 @@ defmodule FarmbotOS.BootupSequenceWorker do {:noreply, state} %{name: name} -> - Logger.debug("bootup sequence start: #{inspect(state)}") + Logger.debug("| bootup sequence | start_sequence ok #{inspect(state)}") FarmbotCore.Logger.busy(2, "Starting bootup sequence: #{name}") ref = make_ref() - FarmbotCeleryScript.execute(execute_ast(id), ref) + ast = execute_ast(id) + worker_pid = self() + _pid = spawn(FarmbotCeleryScript.StepRunner, :step, [worker_pid, ref, ast]) {:noreply, %{state | sequence_started_at: DateTime.utc_now(), sequence_ref: ref}} end end @@ -77,6 +86,7 @@ defmodule FarmbotOS.BootupSequenceWorker do {BotState, %{changes: %{informational_settings: %{changes: %{idle: idle}}}}}, state ) do + Logger.debug("| bootup sequence | idle ok") state = maybe_start_sequence(%{state | firmware_idle: idle}) {:noreply, state} end @@ -97,8 +107,10 @@ defmodule FarmbotOS.BootupSequenceWorker do ) do # this should really be fixed upstream not to dispatch if version is none. if state.firmware_version == "none" do + Logger.debug("| bootup sequence | firmware_configured err") {:noreply, state} else + Logger.debug("| bootup sequence | firmware_configured ok") state = maybe_start_sequence(%{state | firmware_configured: fw_configured}) {:noreply, state} end @@ -108,12 +120,14 @@ defmodule FarmbotOS.BootupSequenceWorker do {BotState, %{changes: %{informational_settings: %{changes: %{sync_status: "synced"}}}}}, state ) do + Logger.debug("| bootup sequence | synced ok") state = maybe_start_sequence(%{state | synced: true}) {:noreply, state} end - def handle_info({BotState, _}, state) do - state = maybe_start_sequence(%{state | synced: true}) + # def handle_info({BotState, _}, state) do + def handle_info(_, state) do + state = maybe_start_sequence(state) {:noreply, state} end @@ -124,13 +138,32 @@ defmodule FarmbotOS.BootupSequenceWorker do defp maybe_start_sequence(%{sequence_started_at: %DateTime{}} = state), do: state defp maybe_start_sequence(%{sequence_completed_at: %DateTime{}} = state), do: state + defp maybe_start_sequence(%{farmwares_loaded: false} = state) do + farmwares = FarmbotCore.DepTracker.get_asset(FarmbotCore.Asset.FarmwareInstallation) + + loaded = + Enum.all?(farmwares, fn + {{FarmbotCore.Asset.FarmwareInstallation, _id}, :complete} -> true + _ -> false + end) + + loaded && Logger.debug("| bootup sequence | farmware_loaded ok") + + if loaded, + do: maybe_start_sequence(%{state | farmwares_loaded: true}), + else: state + end + defp maybe_start_sequence(state) do case Asset.fbos_config() do %{boot_sequence_id: nil} -> + Logger.debug("| bootup sequnce | assets_loaded noop") state %{boot_sequence_id: id} -> - dependency_assets_loaded?() && send(self(), :start_sequence) + loaded? = dependency_assets_loaded?() + Logger.debug("| bootup sequnce | assets_loaded ok") + loaded? && send(self(), :start_sequence) %{state | sequence_id: id} end end diff --git a/farmbot_os/mix.exs b/farmbot_os/mix.exs index f84e32ec..57ec73bb 100644 --- a/farmbot_os/mix.exs +++ b/farmbot_os/mix.exs @@ -67,7 +67,7 @@ defmodule FarmbotOS.MixProject do def application do [ mod: {FarmbotOS, []}, - extra_applications: [:logger, :runtime_tools, :eex] + extra_applications: [:logger, :runtime_tools, :eex, :inets] ] end