Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is with and try/rescue can be same in elixir

Tags:

elixir

I am trying to handle an error coming in a result of an HTTPoison.request! with

try do
  %{"session_id" => session_id} = ElixirDropbox.Files.UploadSession.start(client, true, image_save_path)
  write_sessional_values(session_id, file_size, "/#{construction}/#{camera_exid}/#{id}/#{starting}.jpg", path)
  check_1000_chunk(path) |> length() |> commit_if_1000(client, path)
rescue
  _ ->
    :timer.sleep(:timer.seconds(3))
    upload(200, response, starting, camera_exid, id, requestor)
end

my question is: I am totally ignoring the exception in rescue and doing the operation again which I want to do.

same as in with..

with {:ok, file_size} <- get_file_size(image_save_path),
     %{"session_id" => session_id} <- ElixirDropbox.Files.UploadSession.start(client, true, image_save_path) do             
  write_sessional_values(session_id, file_size, "/#{construction}/#{camera_exid}/#{id}/#{starting}.jpg", path)
  check_1000_chunk(path) |> length() |> commit_if_1000(client, path)
else
  _ ->
    :timer.sleep(:timer.seconds(3))
    upload(200, response, starting, camera_exid, id, requestor)        
end

I am totally ignoring what is coming in else part in with what are the solid grounds here to use both in which cases?

like image 766
Junaid Farooq Avatar asked Jan 30 '26 22:01

Junaid Farooq


1 Answers

with is used when you want to make sure that a number of steps ensure that the right data is available in your application before you can perform the task. A common example would be to make sure that fields exist in a map:

with {:ok, width} when not is_nil(width) <- Map.fetch(data, :width),
     {:ok, height} when not is_nil(height) <- Map.fetch(data, :height) do
   {:ok, width * height}
else
  _error ->
    {:error, "This data does not have the correct values"}
end

You want to use rescue when an exception is thrown that you want to recover from. Here's an example of when you would want to use rescue with the same operation:

try do
  width = Map.fetch!(data, :width)
  height = Map.fetch!(data, :height)
  {:ok, width * height}
rescue
  %KeyError{message: message} ->
    {:error, message}
end

Generally speaking, I prefer to structure my applications in a way that does not use rescue blocks. I would like to know when an error is thrown in the apps that I write so that I can fix something. I believe errors should be expected and exceptions should be an indication that you have a bug.

However, if you're working with a third party library that throws exceptions that you can expect then using rescue blocks is just fine.

The elixir docs are pretty helpful when talking about errors https://elixir-lang.org/getting-started/try-catch-and-rescue.html#errors

In the example you have provided I would recommend that you use a with block because you are expecting that the upload might fail. Also, I would recommend that you specify a max_retries variable that, when reached, throws an exception so you're not infinitely trying to upload something.

On a side note, I believe the recommended way to rescue something is to do it in the function and not a try/rescue block like this:

def my_func(a) do
  do_something(a)
rescue
  %Exception{} ->
    {:error, "ERROR"}
end

I hope this helps.

Cheers!

like image 143
Mike Quinlan Avatar answered Feb 03 '26 01:02

Mike Quinlan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!