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_data
end
This has worked OK, but on a recent github issue, @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_data
end
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 elixir-lang-core+unsubscribe@googlegroups.com.
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.