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.