Further refactor Preloader to allow for error recovery

Previous system would crash the calling processes with a `MatchError`
instead of returning an error. The end result after this commit is
still the same - the auto_sync channel will attempt a resync
every 5 seconds. The log messages/user experience should just
be better now.
pull/974/head
Connor Rigby 2019-06-10 13:38:55 -07:00
parent 11220c3697
commit eefdbfc883
No known key found for this signature in database
GPG Key ID: 29A88B24B70456E0
4 changed files with 55 additions and 21 deletions

View File

@ -57,7 +57,7 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
else
{:error, reason} ->
BotState.set_sync_status("sync_error")
Logger.error("Error preloading. #{reason}")
FarmbotCore.Logger.error(1, "Error preloading. #{inspect(reason)}")
Process.send_after(self(), :preload, 5000)
{:noreply, state}
end

View File

@ -147,22 +147,35 @@ defmodule FarmbotExt.API do
@doc "helper for `GET`ing a path."
def get_body!(path) do
case API.get!(API.client(), path) do
%{body: body, status: 200} ->
case API.get(API.client(), path) do
{:ok, %{body: body, status: 200}} ->
{:ok, body}
%{body: error, status: status} ->
msg = """
HTTP Error getting: #{path}
Status Code = #{status}
{:ok, %{body: error, status: status}} when is_binary(error) ->
get_body_error(path, status, error)
#{error}
"""
{:ok, %{body: %{"error" => error}, status: status}} when is_binary(error) ->
get_body_error(path, status, error)
{:error, msg}
{:ok, %{body: error, status: status}} when is_binary(error) ->
get_body_error(path, status, inspect(error))
{:error, reason} ->
{:error, reason}
end
end
defp get_body_error(path, status, error) when is_binary(error) do
msg = """
HTTP Error getting: #{path}
Status Code = #{status}
#{error}
"""
{:error, msg}
end
@callback get_changeset(module) :: {:ok, %Ecto.Changeset{}} | {:error, term()}
@callback get_changeset(data :: module | map(), Path.t()) ::
{:ok, %Ecto.Changeset{}} | {:error, term()}

View File

@ -10,7 +10,11 @@ defmodule FarmbotExt.API.EagerLoader do
require Logger
use GenServer
@doc "Does a ton of HTTP requests to preload the cache"
@doc """
Does a ton of HTTP requests to preload the cache
Failure in this function is less than ideal and should probably return an
error
"""
def preload(%Sync{} = sync) do
SyncGroup.all_groups()
|> Enum.map(fn asset_module ->
@ -24,14 +28,23 @@ defmodule FarmbotExt.API.EagerLoader do
end)
|> List.flatten()
|> Enum.map(&Task.await(&1, :infinity))
|> Enum.reduce([], fn
{:ok, changeset}, errors ->
:ok = cache(changeset)
errors
:ok
error, errors ->
[error | errors]
end)
|> case do
[] -> :ok
errors -> {:error, errors}
end
end
def preload(asset_module, %{id: id}) when is_atom(asset_module) do
local = Repo.one(from(m in asset_module, where: m.id == ^id)) || asset_module
{:ok, changeset} = API.get_changeset(local, id)
:ok = cache(changeset)
API.get_changeset(local, id)
end
@doc "Get a Changeset by module and id. May return nil"

View File

@ -34,7 +34,7 @@ defmodule FarmbotExt.API.Preloader do
FarmbotCore.Logger.success(3, "Successfully synced bootup resources.")
:ok = maybe_auto_sync(sync_changeset, auto_sync_change || Query.auto_sync?())
maybe_auto_sync(sync_changeset, auto_sync_change || Query.auto_sync?())
end
end
@ -52,19 +52,27 @@ defmodule FarmbotExt.API.Preloader do
|> Repo.transaction()
FarmbotCore.Logger.success(3, "bootup auto sync complete")
:ok
else
error -> FarmbotCore.Logger.error(3, "bootup auto sync failed #{inspect(error)}")
error ->
FarmbotCore.Logger.error(3, "bootup auto sync failed #{inspect(error)}")
error
end
:ok
end
# When auto_sync is disabled preload the sync.
defp maybe_auto_sync(sync_changeset, false) do
FarmbotCore.Logger.busy(3, "preloading sync")
sync = Changeset.apply_changes(sync_changeset)
EagerLoader.preload(sync)
FarmbotCore.Logger.success(3, "preloaded sync ok")
:ok
case EagerLoader.preload(sync) do
:ok ->
FarmbotCore.Logger.success(3, "preloaded sync ok")
:ok
error ->
FarmbotCore.Logger.error(3, "Failed ot preload sync")
error
end
end
end