Watki

Mam problem z utworzeniem poprawnie watkow dla metody:

def self.prepare_results_for_scripts(scripts, path) threads = [] scripts.find_each do |script| threads << Thread.new(script) { |qa_script| begin puts "#{qa_script.title} in progresss..." self.process_script(qa_script, path) rescue DBI::DatabaseError => e admin_email = EMAIL_CONFIG['login'] err_message = "An error occured with script: " + "#{qa_script.title} - " + "#{e.errstr}" AlertMailer.send_alert(admin_email, err_message).deliver next end } end threads.each { |aThread| aThread.join } end
W metodzie tej tworze tablice watkow z ktorych kazdy wywoluje metode process_script

def self.process_script(script, path) users = User.find_script_users(script) report_title = script.title if script.email_form? result_array, name_of_columns = self.return_database_result(script)[0..1] users.each { |user| ReportMailer.send_html_report_email(user, name_of_columns, result_array, report_title).deliver } else report_attachment_name, path_to_excel_file = self.create_excel_file(script, path) users.each { |user| ReportMailer.send_excel_report_email(user, report_attachment_name, path_to_excel_file, report_title).deliver } end end
Niestety nie wszystkie watki sa ukonczone tzn ostatni raport nie jest wyslany z powodu tego bledu:

[code]1 in progresss…2 in progresss…
3 in progresss…
4 in progresss…5 in progresss…
6 in progresss…

Processing script: 1Processing script: 2
Processing script: 3Processing script: 4
Processing script: 5
Processing script: 6================================================================================

scheduler caught exception:
Expected /home/lukasz/Projects/sp-qas/qas/app/mailers/report_mailer.rb to define ReportMailer
/usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:503:in load_missing_constant' /usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:192:inblock in const_missing’
/usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:190:in each' /usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:190:inconst_missing’
/usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:514:in load_missing_constant' /usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:192:inblock in const_missing’
/usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:190:in each' /usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activesupport-3.2.2/lib/active_support/dependencies.rb:190:inconst_missing’
/home/lukasz/Projects/sp-qas/qas/lib/report.rb:51:in block in process_script' /usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activerecord-3.2.2/lib/active_record/relation/delegation.rb:6:ineach’
/usr/local/rvm/gems/ruby-1.9.3-p0@sp_qas/gems/activerecord-3.2.2/lib/active_record/relation/delegation.rb:6:in each' /home/lukasz/Projects/sp-qas/qas/lib/report.rb:51:inprocess_script’
/home/lukasz/Projects/sp-qas/qas/lib/report.rb:32:in `block (2 levels) in prepare_results_for_scripts’

^C>> Stopping …[/code]
W wyniku zostaje przeslanych tylko 5 raportow zamiast 6

autoload nie jest thread safe, powinieneś zrobić w tym pliku:

require_dependency 'report_mailer'

Oraz, jeżeli te skrypty używają bazy danych, to lepiej nie robić ich więcej niż połączeń do bazy. W database.yml masz prawdopodobnie pool: 5, więc najlepiej użyj jakiegoś threadpool (możesz to bardzo prosto zrobić używając queue)

Hej drogus, dziekuje za odpowiedz. require_dependency ‘report_mailer’ pomoglo. Czy moglbys mi wytlumaczyc dlaczego musze to dodac jesli uzywam watkow oraz kiedy aplikacja wysyla emaile w tych watkach.

Drugi problem, przed twoja odpowiedzia zwiekszylem pool w database.yml do 10 ale oczywiscie skryptow bewdzie wiecej niz 10 zdefiniowanych w aplikacji. Co moglbys mi polecic to stworzenia takiej kolejki watkow? Czy inicjujac taka kolejke musze podac liczbe obslugiwanych skryptow i dopiero stworzyc odpowiedni rozmiar kolejki? Np majac 10 skryptow do obslugi musze stworzyc Queue(10) ?

Krótka odpowiedź jest powyżej: autoload nie jest thread safe :wink:

Dłuższa odpowiedź: w trybie development podczas używania nieznanej stałej, wykonywana jest metoda const_missing, która zajmuje się załadowaniem pliku z tą stałą. Jeżeli kilka wątków próbuje załadować dany plik, to może pojawić się problem, ale nie jestem w stanie powiedzieć na czym to dokładnie polega, bo nigdy nie chciało mi się zaglądać do Autoload w railsach.

Powinieneś zdefiniować raczej ilość wątków, które będą korzystać z tej kolejki. Ale tak właściwie, jeżeli nie jesteś pewien jak to zrobić, to najlepiej poszukaj jakiejś implementacj ThreadPool, a swoje własne rozwiązanie napisz najpierw do nauki, będzie bezpieczniej :wink:

OK wiec tak, skorzystalem z tej implementacji:

http://burgestrand.se/code/ruby-thread-pool/

Skrypty sa wykonywane ale emaile nie sa wysylane do uzytkownikow w moich testach. Aplikacja nie wyrzuca zadnych bledow. Oto moj kod:

report.rb

[code]require ‘exasol’
require ‘excel’
require ‘threadpool’
require_dependency ‘report_mailer’

def self.prepare_results_for_scripts(scripts, path)
size = scripts.count
pool = Pool.new(size)
scripts.find_each do |script|
pool.schedule do
begin
puts “#{script.title} in progresss…”
self.process_script(script, path)
rescue DBI::DatabaseError => e
admin_email = EMAIL_CONFIG[‘login’]
err_message = "An error occured with script: " + "#{script.title} - " + “#{e.errstr}”
AlertMailer.send_alert(admin_email, err_message).deliver
next
end
end
end
at_exit { pool.shutdown }
end[/code]
threadpool.rb

[code]require ‘thread’

class Pool

def initialize(size)
@size = size
@jobs = Queue.new

@pool = Array.new(@size) do |i|
  Thread.new do
    Thread.current[:id] = i
    catch(:exit) do
      loop do
        job, args = @jobs.pop
        job.call(*args)
      end
    end
  end
end

end

def schedule(*args, &block)
@jobs << [block, args]
end

def shutdown
@size.times do
schedule { throw :exit }
end
@pool.map(&:join)
end
end[/code]
Oto przykladowy output z aplikacji. Zadnych bledo ale emaile nie sa wysylane:

[code]rails s
=> Booting Thin
=> Rails 3.2.2 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server

Thin web server (v1.4.1 codename Chromeo)
Maximum connections set to 1024
Listening on 0.0.0.0:3000, CTRL+C to stop
6
Blocked payouts due to the FRAUD(CLICK) logic in progresss…
das in progresss…eqweqwe in progresss…
5 in progresss…
ap in progresss…

423423 in progresss…Processing script: Blocked payouts due to the FRAUD(CLICK) logic
Processing script: eqweqweProcessing script: 5

Processing script: ap
Processing script: das
Processing script: 423423[/code]