Resque, Rails 4 i timeout

Hej,

mam aplikacje ktora uzywa gemu Resque i Rails 4. Aplikacja ta wykonuje zapytani do bazy z czestotliwoscia zedfiniowana w crontabie (whenever gem): co godzine, co dzien itd. Jesli w danym czasie jest kilka raportow resque tworzy kolejke jobow oblugiwana przez 2 workery. Przy czym, zanim kolejka ta zostanie stworzona sprawdzam czy baza danych jest up-do-date. Po tym sprawdzeniu tworzona jest kolejka i wszystko dziala jak nalezy. Raporty sa wysylane przez aplikacje.

Problem powstaje gdy to samo chce wykonac z poziomu aplikacji. Kazdy raport jest zapisany w bazie. Dla kazdego raportu jest stworzona metoda w kontrolerze ktora pozwala na wyslanie tego raportu recznie. Problem w tym ze przed wysylaniem i stworzeniem kolejki sprawdzam jednorazowo czy baza danych jest up-to-date. Poniewaz zapytanie to chwilke trwa i czas oczekiwania na rezultat moze byc wiekszy niz 30 sekund aplikacja dostaje timeouty i raport nie jest wysylany. Mozliwym rozwiazaniem byloby dodac to sprawdzenie do kolejki ale w tym przypadku to samo zapytanie byloby uruchamiane przed kazdym raportem podczas uruchomienia cronjoba. Wiec jesli w danym momencie jest 15 raportow sprawdzanie czy baza danych jest up-to-date wykonywane byloby 15 razy co nie ma sensu i nie jest wydajne.

Ponizej kod i klasa:

class ReportMaintenance
  def self.process(scripts)
    if DB.uptodate? #tutaj aplikacja dostaje timeout
      Report.generate(scripts)
    else
      #send alert email
    end
  end
end

Klasa Report:

class Report
  def self.generate(scripts)
    scripts.each do |script|
      Resque.enqueue(SendReportJob, script.id)
    end
  end
end

Kolejka jest tworzona w klasie SendReportJob:

class SendReportJob 
  def self.queue
    :reporting
  end

  def self.perform(script_id)
    script = Script.find(script_id)
    work(script)
  end

  def self.work(script)
    content = DB.execute_query(script)
    ReportMailer.send_file(content).deliver
  end
 end

Czy macie jakis pomysl jak to rozwiazac?

Dlaczego sprawdzanie ,ze baza jest up to date tyle trwa? Kiedy baza jest up to date, a keidy nie?

To co bym zrobil, to stworzenie nowego joba, ktory by sie dodawal do kolejki po wywolaniu url, i raport by czekal pod jakims url (mozesz zwrocic kod 202), lub na maila.

Hej Slawosz,

to nie jest baza aplikacji: sprawdzanych jest kilka tabel ktore sa najwazniejsze za pomoca jednego zapytania. Czasem to trwa dluzej zwlaszcza jesli w bazie sa uruchomione inne zapytania ktore wplywaja na czas otrzymania rezultatu.

Musze chyba jednak odseparowac te dwie czynnosci: wysylanie raportow za pomoca crona i za pomoca polecenia “Wyslij aport” (metoda w kontrolerze) - teraz aplikacja korzysta ze wspolnego kodu. W przypadku crona aplikacja nie ma problemow jesli nawet zapytanie up-to-date trwa wiecej niz 30 sekund. W przypadku metody kontrolera jest to juz problem i aplikacja zwraca timeout.

A myślałeś może o asynchronicznym procesowaniu pliku z pomocą napisanego już background workera?

Naciskasz przycisk “Wyślij raport” -> leci request XHR do railsów -> strona wie, że raport się tworzy, więc pinguje również asynchronicznie dany URL aż raport się pojawi (a u klienta w przeglądarce wystarczy prosty popup "Please wait until your report is ready) -> raport się pojawił -> wyślij do klienta.

Dzięki temu zawsze mógłbyś procesować w background workerze.

Hej,

dzieki za propozycje. Wlasnie chce to zaimplementowac. Dam znac jak poszlo.

Pozdrawiam