I’m working on a bit of code that offloads a DB query to a task. The result of the DB query isn’t absolutely necessary to provide a response but provides some extra metadata that the user can do without in a pinch. If the DB query takes too long or fails, I’d like to degrade gracefully and provide an incomplete response.
I’ve got it degrading nicely when the query takes too long by using Task.yield:
task = Task.async(fn -> run_query end)
# do other work
results = case Task.yield(task, timeout) do
{ :ok, results } -> results
nil ->
Task.shutdown(task)
Logger.info "Task timed out..."
[]
end
I can’t figure out how to deal with errors (e.g. DB connection failures) in the query, though. I don’t want my main process to crash if there’s a query failure. Task.async/1 links the processes so they mutually crash. The Task docs suggest using Task.start_link/1 when you don’t want the processes linked, but I’m not sure how to get the result back when using Task.start_link/1 as it does not return a task.
Any suggestions for how to do this?
Thanks,
Myron
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/011e2e4a-3864-4588-b995-4a5df748e8f1%40googlegroups.com.
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-talk" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-talk/rblNhLwYtuw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/0ce44aef-4159-4a61-ab07-64725663e695%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/849E4B00-E3D0-456C-9E12-700C2BFCDED3%40gmail.com.
This is very enlightening discussion, so thank you both :).
He knows exactly the case he wants to handle.
I don’t know the exact exceptions I want to handle. I’d have to dig through ecto and mariex to see what all the possible exceptions are and that’s not a particularly appealing approach here. I don’t see how any throws or process exits could happen here so using catch type, error feels like overkill. I’m thinking of using the following:
task = Task.async fn ->
try do
run_query
rescue
ex ->
log_exception(ex)
[]
end
end
One part I’m unsure about is log_exception: I can format a message for Logger.error easy enough but exceptions raised in tasks are usually already logged with a well-formatted message including stacktrace, etc. Is there something provided in the stdlib that will format the exception for me so I don’t have to format it myself when logging it?
On a side note, I read through the getting started page on try, catch and rescue and the docs on try and I don’t see anything that mentions that catch can be used to handle exceptions. Perhaps the docs could be improved to mention this? I’d work up a PR myself if not for the fact that my understanding of this area of elixir is still very limited.
Thanks,
Myron
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/CAGnRm4Kgxo6JDw8MFTU5sbe0KGv_kh-gjtunyKmUjK9ovXHjDw%40mail.gmail.com.
On 01 Nov 2015, at 00:03, José Valim <jose....@plataformatec.com.br> wrote:tl;dr: explicitly list the cases you want to rescue/catch. Avoid catch-alls.I have to strongly disagree with this one, Saša. :)You generally want to explicitly list the cases you want to rescue. Otherwise, there is a very high chance you end-up catching errors that come from actual bugs that may have other consequences in the system. And if you forget to log, you may never find those out.From the original message by Myron: "I’ve got it degrading nicely when the query takes too long". He knows exactly the case he wants to handle. Surely, there are some cases you want to use "catch" but they are by large the exception. Furthermore, 99% of the times I use the "catch kind, reason" syntax I end-up re-raising what I caught anyway.
Finally, once you catch the error, you change the exit status of the Task, which is particularly worrying when you spawn other tasks from the parent task. And catching all just increase the chances you end-up catching something you really should not, affecting involved processes.