srinivasu

srinivasu

Best Practises for Error handling elixir?

How to handle excepions in elixir?
Suppose i have A, B, C ,D, E modules. and each module has get() function.
A.get() method will call the B.get() method.
B.get() method will call the C.get() method like D.get() method will call the E.get() method for some calculations.
suppose if i am gettting an error in E.get() method then thow to pass that error too A.get() method.
i need best practises for this case.
is it need to catching the error in all the modules and and re throwing to parent module?

Most Liked

NobbZ

NobbZ

A common pattern in this case is to have a get/x and a get!/x function (where x is the arity).

The unbanged version does return a tuple which first element is either :ok or :error while the second element is the result of the computation or the reason of failure (atom or string) depending on the first tuple.

The banged version on the other hand does either return the result of the computation or raises an exeption.

You can observe this pattern very often in the elixir standard library very often, an example of this is Map.fetch/2 and Map.fetch!/2.

The banged version is very often a simple wrapper around the unbanged one as in the following example:

@spec foo(any) :: {:ok, Foo.t} | {:error, String.t}
def foo(bar), do: bar |> do_the_magic

@spec foo!(any) :: Foo.t | no_return
def foo!(bar) do
  case foo(bar) do
    {:ok, result} -> result
    {:error, _}   -> raise FooError
  end
end

In the context of well designed supervision trees you probably do not even need to catch something raised, as well as you probably do not need to handle {:error, _} cases. Just try to match-assign the {:ok, _} and let the process die when it failed.

In the case you really have to handle the errors because of reasons that matter, do not raise, but use signaling tuples as in the unbanged functions, thrown axceptions do add some overhead and do add a significant runtime-cost.

Exceptions are to see exactly as this! An exception, a thing that might happen, but you do not consider it under normal circumstances. Use them only if you really want to fail, do not try to recover from them!

12
Post #4
cmkarlsson

cmkarlsson

Generally it is exactly right. You should only handle returns from a function which you actually can handle. Please don’t program defensively.

You can see {:ok, res} = my_fun() as an assertion which should never fail. (or a failure you can’t do anything about anyway). And if it does fail, the supervisors make sure your application doesn’t crash.

If {error, reason} is something you need to handle in your business logic you deal with it with pattern matching and you should only deal with the errors you care about. Because it is part of business logic you have to deal with is so the “complexity” is unavoidable.

Don’t catch errors and log anywhere except the top level of your code. It is better to bubble up. Error messages should ideally be tuples of atoms with as much information as possible so that you clearly know which sort of errors to handle and which to ignore.

A nice “pattern” in erlang applications is to return atoms {:error, :some_error} and then have the module returning the error being able to format it into a readable string. This means you can bubble up the error message as a tuple and only the code doing the logging translate it to human readable format. It also means the module producing the error is able to give a meaningful message rather than the caller having to make something up.

case MyModule.my_fun() do
  {:ok, res} -> :working_good
  {:error, :some_error} -> {:error, :some_error}
end

and in top level handling code:

case x of
  {:error, reason} -> Logger.log(MyModule.format_error(reason))
end
bobbypriambodo

bobbypriambodo

It’s hard to be specific without knowing your exact use case, but since Elixir code run in processes, the most natural way to handle it is don’t. Let it crash, and let the monitoring process (Supervisor) restarts it. Catching exceptions (using try and rescue) is quite frowned upon I think.

However, it really depends on the nature of the error. Is it often or rare? Is it caused by misbehavior of the outside world, eg. network or hardware fails? The information could help to determine whether or not you need to write code to handle it.

Where Next?

Popular in Questions Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

We're in Beta

About us Mission Statement