Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat :error and :error tuples as function failure #2

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ proceed_with(user_id)

## Semantics

The call to `eventually` will succeed if the passed function returns some value
other than `false` within the provided number of retries. Otherwise, it will
either raise a `Liveness` exception or reraise the last exception raised by the
function.
The call to `eventually` will succeed within the provided number of retries if
the passed function returns some value other than:

* `false`
* `:error`
* a tuple starting with `:error`

Otherwise, it will either raise a `Liveness` exception or reraise the last
exception raised by the function.

By default, `eventually` will attempt to execute the function 250 times, every
20 milliseconds. Both parameters can be altered by passing them to
Expand Down
9 changes: 5 additions & 4 deletions lib/liveness.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ defmodule Liveness do
milliseconds, the next try will be attempted immediately after `f` returns.

A function is deemed to have failed if it returns `false` or `nil` (a falsy
value), or if it crashes (exits, raises, or `:erlang.error`s out).
value), `:error` or a tuple starting with `:error`, or if it crashes (exits,
raises, or `:erlang.error`s out).

If the function returns successfully, its return value becomes the value of
the call to `eventually`.

If the function returns a falsy value (`false` or `nil`) upon the last try,
then the `Liveness` exception is raised.
If the function fails upon the last try, then the `Liveness` exception is
raised.

If the function raises an exception upon the last try, this exception is
re-raised by `eventually` with the *original* stacktrace.
Expand All @@ -45,7 +46,7 @@ defmodule Liveness do

try do
case f.() do
x when is_nil(x) or false == x ->
x when is_nil(x) or false == x or :error == x or (is_tuple(x) and elem(x, 0) == :error) ->
sleep_remaining(started_at, interval)
exception = %__MODULE__{message: "function returned #{inspect(x)}"}
eventually(f, tries - 1, interval, exception, nil)
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule Liveness.MixProject do
def application, do: []

defp deps do
[{:ex_doc, "~> 0.21.2", only: :dev, runtime: false}]
[{:ex_doc, "~> 0.0", only: :dev, runtime: false}]
end

defp docs do
Expand Down
12 changes: 7 additions & 5 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
%{
"earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"},
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
}
20 changes: 20 additions & 0 deletions test/liveness_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ defmodule LivenessTest do
test "it returns value immediately if fun neither returns false nor raises" do
assert eventually(fn -> 123 end) == 123
assert eventually(fn -> :ok end) == :ok
assert eventually(fn -> {:ok, 123} end) == {:ok, 123}
assert eventually(fn -> {:ok, 123, 456} end) == {:ok, 123, 456}
assert eventually(fn -> "foo" end) == "foo"
end

Expand All @@ -21,6 +23,24 @@ defmodule LivenessTest do
end
end

test "it raises an exception if fun returns :error" do
assert_raise Liveness, "function returned :error", fn ->
eventually(fn -> :error end, 2, 20)
end
end

test "it raises an exception if fun returns a tuple with :error as the first element" do
assert_raise Liveness, ~s(function returned {:error, "Something went wrong"}), fn ->
eventually(fn -> {:error, "Something went wrong"} end, 2, 20)
end

assert_raise Liveness,
~s(function returned {:error, "Something went wrong", :server_error}),
fn ->
eventually(fn -> {:error, "Something went wrong", :server_error} end, 2, 20)
end
end

test "it raises an exception that fun raises" do
assert_raise ArgumentError, "this is an argument error", fn ->
eventually(fn -> raise(ArgumentError, "this is an argument error") end, 2, 20)
Expand Down