In our application, we commonly use tasks while responding to HTTP requests 
to fetch metadata from the database that is used to “decorate” the returned 
data with some non-essential bits of info (think things like tags, added_at 
timestamps, etc). Given that this data is non-essential, we only want to 
wait on the task for a limited amount of time, and if the database query 
has not completed in that time, then we just want to respond without the 
extra data. We’ve tended to use this pattern:

task = Task.async(fn -> perform_db_query(...) end)
main_data = perform_main_request_logic(...)
case Task.yield(task, timeout) do
  {:ok, result} -> merge_metadata(main_data, result)
  nil ->
    Task.shutdown(task)
    main_dataend

This has worked OK, but on a recent github issue 
<https://github.com/elixir-lang/elixir/issues/5277#issuecomment-250872428>, 
@fishcakez helped me realize there’s a race condition in this pattern. The 
task could complete between the call to Task.yield/2 and Task.shutdown/1, 
and the logic as I’ve written it would throw the result away. Instead, it 
is better to do this at the end:

case Task.yield(task, timeout) || Task.shutdown(task) do
  {:ok, result} -> merge_metadata(main_data, result)
  nil -> main_dataend

Given that it’s an easy mistake to make, I think it would be beneficial if 
Task.yield(task, 
timeout) || Task.shutdown(task) was encapsulated as a function on the Task 
module. Maybe something like Task.finish/2. Basically, it’s like 
Task.await/2, but with a couple differences:

If the task completes, it returns {:ok, result} instead of just result
If the task times out, it returns nil instead of causing an exit.

If we weren’t concerned with backwards compatibility, it would make sense 
to rename Task.await/2 to Task.await!/2 and then make this Task.await/2 — 
but obviously we can’t do that. Task.finish/2 is the best name I’ve been 
able to come up with.

Thoughts?

Myron
​

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/146cc734-b511-44d7-b647-5a1bf0dd37f3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to