задания cron в rails 3 через rake

В этой статье, я персонально для себя, опишу метод запуска задания cron в Ruby on Rails 3 через rake. Об этом способе я узнал из  комментария к статье задания cron в ROR 3, который написал Леонид Шевцов, приведя ссылку на railscasts.com.

На railscasts есть видео на английском показывающее как запускать Ruby-код, использующий все преймущества Active Records, а точнее работающий в среде вашего rails-приложения. Я же хочу просто резюмировать это видео и привести его в текстовый вид, заодно проверив все это на собственном опыте.

запись и запуск кода

Начнем с того, что если вы наберете команду $ rake -T, то сможете увидеть список и описание всех команд rake.
Теперь подробнее. Заходим в rails_app/lib/tasks/ и создаем файл, где собственно и будет наш код – rails_app/lib/tasks/crontask.rake.
Открываем его и пишем для начала так:

1
2
3
task :greet do
	puts 'Hello world!'
end

Возвращаемся в консоль:

1
2
3
$ rake greet
(in /home/myusername/rails3/rails_app)
Hello world!

В это файл можно прописать сколь угодно много таких task’ов и каждый из них будет запускатся согласно rake <task_name>.

цепочка заданий

Усложним пример, добавив в файл еще одна задание – :ask:

1
2
3
4
5
6
task :greet do
	puts 'Hello world!'
end
task :ask => :greet do
	puts 'How are u?!'
end

Теперь по вызову задания ask первоначально будет запускатся цепь: greet->ask:

1
2
3
4
$ rake ask
(in /home/myusername/rails3/rails_app)
Hello world!
How are u?!

запуск в среде rails-приложения

Если попытаться использовать в задании в таком виде какие-нибудь ресурсы среды вашего приложения, а иначе говоря обращаться к БД через Active Records, то ничего не получится.
Например:

1
2
3
4
task :first_nah do
	product=Product.first
	puts product.title
end
1
2
3
4
$ rake first_nah
(in  /home/myusername/rails3/rails_app)
rake aborted!
uninitialized constant Product

Чтобы все было четко делаем по логике ‘запуска цепочки’ т.е. если нам нужна среда – запустим среду:

1
2
3
4
task :nah_first => :environment do
	product=Product.first
	puts product.title
end

пространство имен

Допустим есть несколько заданий имеющих непосредственное отношение друг к другу, быть может они даже имеют схожие имена.

1
2
3
4
5
6
7
8
9
task :nah_first => :environment do
	product=Product.first
	puts product.title
end
 
task :nah_last => :environment do
	product=Product.last
	puts product.title
end

В таком случае их можно запихнуть в одну группу, пространство имен.

1
2
3
4
5
6
7
8
9
10
namespace :nah do
	task :first => :environment do
		product=Product.first
		puts product.title
	end
	task :last => :environment do
		product=Product.last
		puts product.title
	end
end

В консоли:

1
2
3
4
5
6
$ rake nah:last
(in /home/myusername/rails3/rails_app)
Last_product
$ rake nah:first
(in /home/myusername/rails3/rails_app)
First_product

группы заданий

Если не хотите напрягаться и запускать каждое задание новой командой, можно объединить задания в группу.

1
2
3
4
namespace :nah do
        #код заданий :first и :last
	task :all => [:first,:last]
end

В консоли:

1
2
3
4
$ rake nah:all
(in /home/myusername/rails3/rails_app)
First_product
Last_product

методы в rake

Пусть в заданиях повторяется один и тот же код, допустим это запрос БД. В таком случае целесообразно прописать его один раз в метод.

1
2
3
4
5
6
7
8
9
10
11
12
namespace :shop do
	task :product => :environment do
		product=Product.where('id > ?',20).first
		puts product.title
	end
 
	task :categor => :environment do
		cat=Categor.where('id > ?',20).first
		puts cat.title
	end
	task :all => [:product,:categor]
end

В таком случае лучше сделать метод, который будет выполнять этот запрос.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace :shop do
	task :product => :environment do 
		puts echo(Product).title
	end
 
	task :categor => :environment do 
		puts echo(Categor).title
	end
	task :all => [:product,:categor]
 
	def echo (model_class)
		model_class.where('id > ?',20).first
	end
end

описание заданий

Чтобы не путаться в заданиях, их можно кратко описать.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace :shop do
	desc 'Show first product, which id > 20'
	task :product => :environment do
		puts echo(Product).title
	end
 
	desc 'Show first categor, which id > 20'
	task :categor => :environment do
		puts echo(Categor).title
	end
 
        desc 'Show first product and category'
	task :all => [:product,:categor]
 
	def echo (model_class)
		model_class.where('id > ?',20).first
	end
end

Теперь в консоли можно увидеть справку по командам.

1
2
3
4
5
6
7
$ rake -T
(in /home/myusername/rails3/rails_app)
rake about              # List versions of all Rails...
...
rake shop:all           # Show first product and categor
rake shop:categor       # Show first categor, which id > 20
rake shop:product       # Show first product, which id > 20

3 Comments to “задания cron в rails 3 через rake”

  1. lukmus пишет:

    не смотря на все преймущества rake-метода, здесь все также присутствует ошибка с кодировками:

    rake aborted!
    "\x8B" from ASCII-8BIT to UTF-8
    ...
    /usr/local/lib/ruby/1.9.1/rake.rb:634:in `call'
    /usr/local/lib/ruby/1.9.1/rake.rb:634:in `block in execute'
    /usr/local/lib/ruby/1.9.1/rake.rb:629:in `each'
    /usr/local/lib/ruby/1.9.1/rake.rb:629:in `execute'
    /usr/local/lib/ruby/1.9.1/rake.rb:595:in `block in invoke_with_call_chain'
    /usr/local/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
    /usr/local/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
    /usr/local/lib/ruby/1.9.1/rake.rb:581:in `invoke'
    /usr/local/lib/ruby/1.9.1/rake.rb:2041:in `invoke_task'
    /usr/local/lib/ruby/1.9.1/rake.rb:2019:in `block (2 levels) in top_level'
    /usr/local/lib/ruby/1.9.1/rake.rb:2019:in `each'
    /usr/local/lib/ruby/1.9.1/rake.rb:2019:in `block in top_level'
    /usr/local/lib/ruby/1.9.1/rake.rb:2058:in `standard_exception_handling'
    /usr/local/lib/ruby/1.9.1/rake.rb:2013:in `top_level'
    /usr/local/lib/ruby/1.9.1/rake.rb:1992:in `run'

    Решить ее предлагаю также как и в статье задания cron в ROR 3 через модели.

  2. lukmus пишет:

    если такая же ошибка с кодировками появляется в контроллере:
    invalid multibyte char (US-ASCII)
    то решается она путем добавления в начало файла строки:
    # coding: utf-8

  3. Bighamster пишет:

    Спасибо. Все предельно коротко и ясно.

Leave a Reply to lukmus

(обязательно)

(обязательно)