Queue requests (deferred task) when loading a large CSV file as a background process

This works fine in my controller.

def export_list_sites_as_csv require "csv" csv_string = CSV.generate do |csv| csv << ["id","name", 'etc'] @search.relation.not_archived.each do |site| csv << [site.id, site.name, site.etc] end end send_data csv_string, :type => 'text/csv', :filename => '_sites.csv', :disposition => 'attachment' end 

@search variable depends on the user filter, to the extent that there will be a lot of RAM load , UX is not very good. Because other requests will be suspended until the current request is submitted. Which also makes my system freeze. Therefore, you want to start the background process and tell the user when he will be ready to download.

When I try to switch to a model.

I get an error undefined method `send_data 'for # <\ Class: 0x9f8bed0>

I turn to the model because I have to call delayed work.

Work with CSV and Delayed Job for the first time.

Edit: ActionController::Streaming is only available in the controller so otherwise? more often or not, this is not going anywhere.

As the answer of D-Side says, I have to look for other ways.

Edit2: After http://railscasts.com/episodes/171-delayed-job I was able to do

 class ExportCsv < Struct(:site_ids, :user_id) def perform require "csv" sites = Site.where(id: site_ids) CSV.open("tmp/#{user_id}.csv", "w+") do |csv| csv << ["id","name", 'etc'] sites.each do |site| csv << .... end end end def after(job) send_file( .... ) end end 

How to use ActionController::Streaming inside custom class ExportCsv or Model

Edit:

Understanding synchronization and how I dealt with the situation,

Answer : http://imnithin.imtqy.com/csv_download_with_delayed_job.html

+5
source share
1 answer

What you are trying to do hits the target of DelayedJob.

When a user makes a request, the server must make a response in order to populate it. The problem is that some requests take a lot of time, and the user must hang and wait until this is over. The classic case is bulk email delivery, but there are, as you already mentioned, others, such as creating a dataset. No difference. It will take more time than the time you can afford to wait.

Now comes the DelayedJob. It performs a specific action without the request context for a response. He does not need to rush. But you cannot just push send_data for it: there will be no request for an answer to . Instead, he should record the results of work done in some kind of persistent storage.

You have several ways to remove this.

  • You can inform your user by email when the data set is ready. You can even attach it to an email, but I would not recommend it: you cannot rely on the willingness of email providers to accept a large piece of data. Make a link to download the dataset and submit it.
    • DelayedJob will have to display the data set, save it in a file, get the link and send it by e-mail to the user.
  • Create a section (company model, controller and views) of your application, which sounds like "Completed requests", may be part of the user profile. The β€œstart” request should instruct the user to return later and view this list to get the result.
    • DelayedJob will have to make an entry in this list after filling out the request. How the data set is stored does not matter, but you can combine it with the above method, save it to a file and display a link to it.
+2
source

Source: https://habr.com/ru/post/1207472/


All Articles