Skip to content

Commit

Permalink
improvement: Use Splode for managing errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimsynz committed Mar 14, 2024
1 parent d0fe8d2 commit b995694
Show file tree
Hide file tree
Showing 23 changed files with 115 additions and 52 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"backoff",
"casted",
"mappish",
"Planable"
"Planable",
"splode",
"Splode"
]
}
3 changes: 2 additions & 1 deletion lib/reactor/builder/compose.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ defmodule Reactor.Builder.Compose do
import Reactor, only: :macros
import Reactor.Argument, only: :macros
import Reactor.Utils
alias Reactor.{Argument, Builder, Error.ComposeError, Step}
alias Reactor.Error.Internal.Compose, as: ComposeError
alias Reactor.{Argument, Builder, Step}

@doc """
Compose another Reactor inside this one.
Expand Down
13 changes: 13 additions & 0 deletions lib/reactor/error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Reactor.Error do
@moduledoc """
Uses `splode` to manage various classes of error.
"""

use Splode,
error_classes: [
invalid: Reactor.Error.Invalid,
reactor: Reactor.Error.Internal,
unknown: Reactor.Error.Unknown
],
unknown_error: Reactor.Error.Unknown.Unknown
end
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
defmodule Reactor.Error.ComposeError do
defmodule Reactor.Error.Internal.Compose do
@moduledoc """
An error used when attempting to compose to Reactors together.
"""
defexception [:outer_reactor, :inner_reactor, :message, :arguments]
import Reactor.Utils

@doc false
@impl true
def exception(attrs), do: struct(__MODULE__, attrs)
use Splode.Error,
fields: [:outer_reactor, :inner_reactor, :message, :arguments],
class: :reactor

import Reactor.Utils

@doc false
@impl true
def message(error) do
def splode_message(error) do
[
"""
# Unable to compose Reactors
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
defmodule Reactor.Error.PlanError do
defmodule Reactor.Error.Internal.Plan do
@moduledoc """
An error thrown during the planning of a Reactor.
"""
defexception [:reactor, :graph, :step, :message]
import Reactor.Utils

@doc false
@impl true
def exception(attrs), do: struct(__MODULE__, attrs)
# defexception [:reactor, :graph, :step, :message]

use Splode.Error,
fields: [:reactor, :graph, :step, :message],
class: :reactor

import Reactor.Utils

@doc false
@impl true
def message(error) do
def splode_message(error) do
[
"""
# Unable to plan Reactor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
defmodule Reactor.Error.RetriesExceededError do
defmodule Reactor.Error.Internal.RetriesExceeded do
@moduledoc """
An error used when a step runs out of retry events and no other error is
thrown.
"""
defexception [:step, :retry_count]
use Splode.Error, fields: [:step, :retry_count], class: :reactor

@doc false
@impl true
def exception(attrs), do: struct(__MODULE__, attrs)

@doc false
@impl true
def message(error) do
def splode_message(error) do
"""
# Maximum number of retries exceeded executing step.
Expand Down
7 changes: 7 additions & 0 deletions lib/reactor/errors/invalid.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Reactor.Error.Invalid do

Check warning on line 1 in lib/reactor/errors/invalid.ex

View workflow job for this annotation

GitHub Actions / ash-ci / mix credo --strict

Modules should have a @moduledoc tag.
use Splode.Error, fields: [:errors], class: :unknown

def splode_message(%{errors: errors}) do
Splode.ErrorClass.error_messages(errors)
end
end
10 changes: 10 additions & 0 deletions lib/reactor/errors/invalid/transform_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Reactor.Error.Invalid.Transform do
@moduledoc """
An error which occurs when building and running transforms.
"""
use Splode.Error, fields: [:input, :output, :message], class: :invalid

@doc false
@impl true
def splode_message(error), do: error.message
end
7 changes: 7 additions & 0 deletions lib/reactor/errors/reactor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Reactor.Error.Internal do

Check warning on line 1 in lib/reactor/errors/reactor.ex

View workflow job for this annotation

GitHub Actions / ash-ci / mix credo --strict

Modules should have a @moduledoc tag.
use Splode.Error, fields: [:errors], class: :reactor

def splode_message(%{errors: errors}) do
Splode.ErrorClass.error_messages(errors)
end
end
14 changes: 0 additions & 14 deletions lib/reactor/errors/transform_error.ex

This file was deleted.

7 changes: 7 additions & 0 deletions lib/reactor/errors/unknown.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Reactor.Error.Unknown do

Check warning on line 1 in lib/reactor/errors/unknown.ex

View workflow job for this annotation

GitHub Actions / ash-ci / mix credo --strict

Modules should have a @moduledoc tag.
use Splode.Error, fields: [:errors], class: :unknown

def splode_message(%{errors: errors}) do
Splode.ErrorClass.error_messages(errors)
end
end
11 changes: 11 additions & 0 deletions lib/reactor/errors/unknown/unknown.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Reactor.Error.Unknown.Unknown do
@moduledoc """
An error used to wrap unknown errors.
"""

use Splode.Error, fields: [:error], class: :unknown

def splode_message(%{error: error}) do
Exception.message(error)
end
end
5 changes: 3 additions & 2 deletions lib/reactor/executor/async.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ defmodule Reactor.Executor.Async do
Handle the asynchronous execution of a batch of steps, along with any
mutations to the reactor or execution state.
"""
alias Reactor.Error.Internal.RetriesExceeded, as: RetriesExceededError
alias Reactor.Executor.ConcurrencyTracker
alias Reactor.{Error, Executor, Step}
alias Reactor.{Executor, Step}
require Logger

@doc """
Expand Down Expand Up @@ -276,7 +277,7 @@ defmodule Reactor.Executor.Async do
reason

{step, :retry} ->
Error.RetriesExceededError.exception(
RetriesExceededError.exception(
step: step,
retry_count: Map.get(state.retries, step.ref)
)
Expand Down
5 changes: 3 additions & 2 deletions lib/reactor/executor/sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ defmodule Reactor.Executor.Sync do
the reactor or execution state.
"""

alias Reactor.{Error, Executor, Step}
alias Reactor.Error.Internal.RetriesExceeded, as: RetriesExceededError
alias Reactor.{Executor, Step}

@doc """
Try and run a step synchronously.
Expand All @@ -22,7 +23,7 @@ defmodule Reactor.Executor.Sync do
reactor = drop_from_plan(reactor, step)

error =
Error.RetriesExceededError.exception(
RetriesExceededError.exception(
step: step,
retry_count: Map.get(state.retries, step.ref)
)
Expand Down
3 changes: 2 additions & 1 deletion lib/reactor/planner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule Reactor.Planner do
between them representing their dependencies (arguments).
"""

alias Reactor.{Error.PlanError, Step}
alias Reactor.Error.Internal.Plan, as: PlanError
alias Reactor.Step
import Reactor, only: :macros
import Reactor.Argument, only: :macros
import Reactor.Utils
Expand Down
3 changes: 2 additions & 1 deletion lib/reactor/step/compose.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ defmodule Reactor.Step.Compose do
"""

use Reactor.Step
alias Reactor.{Argument, Builder, Error.ComposeError, Info, Step}
alias Reactor.Error.Internal.Compose, as: ComposeError
alias Reactor.{Argument, Builder, Info, Step}
import Reactor, only: :macros
import Reactor.Argument, only: :macros
import Reactor.Utils
Expand Down
3 changes: 2 additions & 1 deletion lib/reactor/step/transform_all.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ defmodule Reactor.Step.TransformAll do
"""

use Reactor.Step
alias Reactor.{Error.TransformError, Step.Transform}
alias Reactor.Error.Invalid.Transform, as: TransformError
alias Reactor.Step.Transform

@doc false
@impl true
Expand Down
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ defmodule Reactor.MixProject do
defp deps do
[
{:spark, "~> 2.0"},
{:splode, "~> 0.1.0"},
{:libgraph, "~> 0.16"},
{:telemetry, "~> 1.2"},

Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
"sourceror": {:hex, :sourceror, "1.0.1", "ec2c41726d181adce888ac94b3f33b359a811b46e019c084509e02c70042e424", [:mix], [], "hexpm", "28225464ffd68bda1843c974f3ff7ccef35e29be09a65dfe8e3df3f7e3600c57"},
"spark": {:hex, :spark, "2.0.1", "6701ca7908923767f60d1a9df7274053e2f7c8a0a594452006d038b05193e450", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "cc3c871dc40184edf2253d1fffcaa931856dac28c6990c4a202bc61f529e266a"},
"splode": {:hex, :splode, "0.1.0", "235d4c434fe6b011cac3d79c71d78c93f5e5a61ff9fd48ad89a0fa549a28ea65", [:mix], [], "hexpm", "82297087099885345ed656c5b360e261cb2e02c822f6a731d470faf2f50585a5"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
"yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"},
Expand Down
13 changes: 12 additions & 1 deletion test/reactor/builder/compose_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
defmodule Reactor.Builder.ComposeTest do
use ExUnit.Case, async: true
alias Reactor.{Argument, Builder, Builder.Compose, Error.ComposeError, Planner, Step, Template}

alias Reactor.Error.Internal.Compose, as: ComposeError

alias Reactor.{
Argument,
Builder,
Builder.Compose,
Planner,
Step,
Template
}

require Reactor.Argument

describe "compose/4" do
Expand Down
5 changes: 3 additions & 2 deletions test/reactor/executor/async_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule Reactor.Executor.AsyncTest do
alias Reactor.{Error, Executor}
alias Reactor.Error.Internal.RetriesExceeded, as: RetriesExceededError
alias Reactor.Executor
import Reactor.Executor.Async
use ExUnit.Case, async: true

Expand Down Expand Up @@ -224,7 +225,7 @@ defmodule Reactor.Executor.AsyncTest do
task = Task.Supervisor.async_nolink(supervisor, fn -> :retry end)
state = %{state | current_tasks: %{task => undoable}, retries: %{undoable.ref => 100}}

assert {:undo, _reactor, %{errors: [%Error.RetriesExceededError{}]}} =
assert {:undo, _reactor, %{errors: [%RetriesExceededError{}]}} =
handle_completed_steps(reactor, state)
end
end
Expand Down
7 changes: 5 additions & 2 deletions test/reactor/executor/sync_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule Reactor.Executor.SyncTest do
alias Reactor.{Error, Executor}
alias Reactor.Error.Internal.RetriesExceeded, as: RetriesExceededError
alias Reactor.Executor
import Reactor.Executor.Sync
use ExUnit.Case, async: true
use Mimic
Expand Down Expand Up @@ -77,7 +78,9 @@ defmodule Reactor.Executor.SyncTest do
|> stub(:run, fn _, _, _ -> :retry end)

state = %{state | retries: Map.put(state.retries, step.ref, 100)}
assert {:undo, _, %{errors: [%Error.RetriesExceededError{}]}} = run(reactor, state, step)

assert {:undo, _, %{errors: [%RetriesExceededError{}]}} =
run(reactor, state, step)
end

test "when the step is successful it tells the reactor to recurse", %{
Expand Down
3 changes: 2 additions & 1 deletion test/reactor/planner_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
defmodule Reactor.PlannerTest do
@moduledoc false
use ExUnit.Case, async: true
alias Reactor.{Builder, Error.PlanError, Info, Planner}
alias Reactor.Error.Internal.Plan, as: PlanError
alias Reactor.{Builder, Info, Planner}

describe "plan/1" do
test "when the argument is not a reactor, it returns an error" do
Expand Down

0 comments on commit b995694

Please sign in to comment.