3. Задача
• Генерация контента (книг) для сайта.
• Входной формат: PDF.
• Выходной формат: SWF.
• Генератор: print2flash.
• Основной приоритет: скорость обработки
(количество публикуемых книг в месяц).
4. Нюансы
• Книги поступают разного качества, часть
из них требует многократной
переработки.
• Print2flash может печатать не более
одного задания за раз в пределах машины.
• Требует windows окружения.
5. Архитектура
• Множественные инсталляции Rails
приложения.
• Общая база.
• Конечный автомат для контроля
состояния задания.
• Отдельные операции - rake таски
запускаемые по крону или планировщику
задач.
11. Почему не очередь
• Так казалось проще.
• Для каждого задания можно одназначно
сказать его статус.
• Единый каталог со всем готовым на
текущий момент контентом.
13. Аудит
https://gist.github.com/949049#file_book.rb
https://github.com/collectiveidea/acts_as_audited
acts_as_audited :except => [:name, :file_name]
https://gist.github.com/949049#file_production.rake
desc "Loads files into Production line"
task :process_batch => :environment do
Audit.as_user("rake:process_batch") do
Book.getFromBatch unless running?("process_batch")
end
end
https://gist.github.com/949049#file_books_controller.rb
def restart
if @book.restartable?
Audit.as_user current_user do
@book.restart_production!
end
flash[:notice] = 'Обработка перезапущена.'
else
flash[:error] = 'Перезапуск невозможен.'
end
redirect_to request.referer
end
15. namespace :munin do
task :config do
puts <<-CONFIG
graph_title Produced pages in last 5 minutes
graph_args -l 0
graph_vlabel pages amount
graph_category App
graph_info This graph shows amount of pages produced
texts.label Text files
docs.label Doc files
views.label View files
quotes.label Quote files
CONFIG
exit 0
end
task :run => :environment do
res = ActiveRecord::Base.connection.execute("select count(nullif(text_ready_time>(now()-'5
minutes'::interval),false)) as c0,count(nullif(doc_ready_time>(now()-'5 minutes'::interval),false)) as
c1,count(nullif(view_ready_time>(now()-'5 minutes'::interval),false)) as
c2,count(nullif(quote_ready_time>(now()-'5 minutes'::interval),false)) as c3 from pages where updated_at >
(now()-'5 minutes'::interval);")
if res
puts "texts.value #{res[0]['c0']}"
puts "docs.value #{res[0]['c1']}"
puts "views.value #{res[0]['c2']}"
puts "quotes.value #{res[0]['c3']}"
end
exit 0
end
end https://gist.github.com/949049#file_munin.rake
16. http://www.nagios.org/
namespace :nagios do
task :abbyy_activity, [:warn, :crit] => :environment do |t, args|
if args.warn and args.crit
states_list = ["loaded", "in_abbyy", "p2f_queue"]
warn_level = args.warn.to_i
crit_level = args.crit.to_i
warn_events = Audit.find(:all, :conditions=>["auditable_type = 'Book' and (username is null or username
ilike 'rake:%') and action = 'update' and created_at > ?", warn_level.minutes.ago])
crit_events = Audit.find(:all, :conditions=>["auditable_type = 'Book' and (username is null or username
ilike 'rake:%') and action = 'update' and created_at > ?", crit_level.minutes.ago])
if (crit_count = crit_events.select{|a| a['changes']['state'] and (a['changes']['state'] &
states_list).size > 1 }).empty?
puts "CRITICAL No state changes at abbyy for #{crit_level} minutes"
exit 2
end
if (warn_count = warn_events.select{|a| a['changes']['state'] and (a['changes']['state'] &
states_list).size > 1 }).empty?
puts "WARNING No state changes at abbyy for #{warn_level} minutes"
exit 1
end
puts "OK Abbyy: state changes #{warn_count.size} for #{warn_level} minutes; state changes
#{crit_count.size} for #{crit_level} minutes."
exit 0
else
exit 3
end
end
https://gist.github.com/949049#file_nagios.rake