-
-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async Barrier for multiple ActiveRecord queries #265
Comments
This code mostly looks good to me. However, you don't need a barrier and can defer the query until rendering by using the following approach: def index
task_query = Task
if @search.present?
task_query = task_query.where('title LIKE ?', "%#{@search}%")
end
@tasks = Async do
task_query.select(:id, :title, :description, :created_at, :updated_at).limit(@per_page).offset(@offset)
end
@count = Async do
task_query.count(:id)
end
end Then, in the view, use it like this: @tasks.wait.each ...
@count.wait ... This will minimise the contention between the controller and view, as the asynchronous tasks will execute "in the background" until you invoke the synchronisation points A complexity of this approach, is if the view fails for any other reason, the child tasks may not be stopped right away, and may execute to completion, even if they aren't needed. However, falcon will typically stop the request task and any child tasks if the request fails outright, so this is usually cleaned up correctly (cancelled). Barriers are useful for when you have an indeterminate number of child tasks, e.g. maybe you need to do an HTTP RPC for each record or something like that, the barrier accumulates and helps you manage all those tasks. If you have a specific number of tasks, you can just start them all (e.g. def index
task_query = Task
if @search.present?
task_query = task_query.where('title LIKE ?', "%#{@search}%")
end
barrier = Async::Barrier.new
# Sync block here will enforce all the following code to execute before the view is rendered:
Sync do
# Start a task to assign to @tasks:
barrier.async do
@tasks = task_query.select(:id, :title, :description, :created_at, :updated_at)
.limit(@per_page)
.offset(@offset)
end
# Start a task to assign to @count:
barrier.async do
@count = task_query.count(:id)
end
# Wait for those tasks to be completed:
barrier.wait
ensure
# If there is any error (or we exit early for any reason), make sure to stop the barrier (and all tasks):
barrier.stop
end
end The above approach ensures that Hope that helps, let me know if you need more clarification. |
Thanks for your explanation. Please forgive if I bothered you. I have another question about the config |
In principle, that is correct. I also believe it's correct in practice, but only in recent versions of Rails. I personally recommend using Rails 8+. |
I'm currently using Rails 8+. If all queries are non-blocking, I don't need to wrap these queries in |
Queries are non-blocking but still sequential so if you want two queries to happen "at the same time" you will need to use |
Thank you for taking time to explain it to me. I only want to ensure that all queries (and if possible, other i/o operations) are non-blocking. That's why I'm trying Falcon for Rails app. |
I'm learning about using Rails with Falcon web server. I want to wait for multiple ActiveRecord queries (something like await Promise.all of Javascript). Does the below code do the same effect?
Please correct me if I'm wrong. Thank you so much.
The text was updated successfully, but these errors were encountered: