铁路的Cron工作:最佳做法?


295

在Rails环境中运行计划任务的最佳方法是什么?脚本/运行者?耙?我想每隔几分钟运行一次任务。


149
对于那些来自Google的用户,请寻求公认的答案之外的其他方法,以寻求更好的方法。
jrdioko 2011年

4
无论何时,答案似乎都比公认的答案更合理,这是一个古老的技巧。
罗布

2
另请注意,至少有一个答案假定您已安装某些宝石。
塔斯(Tass),

一对夫妇的(我发现了什么是)好的做法总结如下wisecashhq.com/blog/writing-reliable-cron-jobs
蒂博BARRERE

在许多情况下,定时任务是难闻的气味。最好通过sidekiq / resque(或其他后台工作者)编写调度程序,或者编写守护程序(功能较少且不可监视的守护程序)。Cron作业至少有几件坏事:1)锁定一次实例很痛苦;2)监控不容易;3)异常处理应再次手动编写;4)不容易重启;5)所有上述问题可由后台工作者轻松解决。
德米特里·普洛什金

Answers:


110

我正在使用rake方法(在heroku的支持下

带有一个名为lib / tasks / cron.rake的文件。

task :cron => :environment do
  puts "Pulling new requests..."
  EdiListener.process_new_messages
  puts "done."
end

要从命令行执行,这只是“ rake cron”。然后可以根据需要将此命令放在操作系统cron / task调度程序上。

更新这是一个相当古老的问题和答案!一些新信息:

  • 我引用的heroku cron服务此后已被替换 Heroku Scheduler
  • 对于频繁执行的任务(尤其是要避免Rails环境启动成本的情况),我的首选方法是使用系统cron调用脚本,该脚本将(a)拨入安全/私有webhook API在后台调用所需的任务或(b)将任务直接放入您选择的排队系统中

在这种情况下,cron条目应该是什么,以便OS知道rake任务的正确路径?
jrdioko

13
注意:这些天我一直在使用(请参阅吉姆·加文的答案),但是运行rake任务的原始cron条目将类似于:30 4 * * * / bin / bash -l -c'cd / opt / railsapp && RAILS_ENV =生产耙的cron --silent”
tardate

1
您如何从控制台称呼它?我做了load "#{Rails.root}/lib/tasks/cron.rake"rake cron,但是得到了NameError:main:Object的未定义局部变量或方法'cron'–
B

3
这种方法的问题是:environment依赖性。我们有一个非常繁重的Rails应用程序,它需要很长时间才能启动,我们的Rake每分钟都会被调用一次,并消耗更多的资源来启动执行任务Rails环境。我很想通过cron调用一个已经启动的 Rails环境,必须在控制器方法和rake环境之间进行调整。
fguillen 2012年

这个任务的持续时间是多长?我正在使用if条件。我想知道它的运行频率。我在heroku网站上找不到关于此的任何信息。
Shubham Chaudhary

254

我已经在非常依赖计划任务的项目上使用了非常受欢迎的“ 每时每刻”功能,这很棒。它为您提供了不错的DSL来定义计划的任务,而不必处理crontab格式。从自述文件:

只要有Ruby gem,它就提供了用于编写和部署cron作业的清晰语法。

自述文件中的示例:

every 3.hours do
  runner "MyModel.some_process"       
  rake "my:rake:task"                 
  command "/usr/bin/my_great_command"
end

every 1.day, :at => '4:30 am' do 
  runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end

22
如果每分钟运行一次,则环境将每次都重新启动,这可能会花费很大。似乎github.com/ssoroka/scheduler_daemon避免了这种情况。
lulalala 2011年

3
+1可使cron配置与您的版本控制系统保持一致
brittohalloran 2011年

3
我认为这是最好的解决方案。如果您使用的是Rails,我认为最好用Rails编写所有内容。通过这种方法,您还可以在更换服务器时忘记cron任务,它随应用程序一起移动。
Adrian Matteo

有一个很棒的Railscast关于everything确实很有帮助(还提供了一个较旧的免费版本)。
aceofbassgreg

@Tony,无论何时,基本上都是用于编写cron作业的领域特定语言。它在Rails服务器上编译成常规的cron语法,而cron是执行您指定的工作的对象(通常是通过rails运行程序)。
格雷格

19

在我们的项目中,我们首先使用了宝石,但是遇到了一些问题。

然后,我们切换到RUFUS SCHEDULER gem,它对于在Rails中安排任务非常简单且可靠。

我们已经使用它来发送每周和每天的邮件,甚至用于运行一些定期的rake任务或任何方法。

在此使用的代码如下:

    require 'rufus-scheduler'

    scheduler = Rufus::Scheduler.new

    scheduler.in '10d' do
      # do something in 10 days
    end

    scheduler.at '2030/12/12 23:30:00' do
      # do something at a given point in time
    end

    scheduler.every '3h' do
      # do something every 3 hours
    end

    scheduler.cron '5 0 * * *' do
      # do something every day, five minutes after midnight
      # (see "man 5 crontab" in your terminal)
    end

要了解更多信息:https : //github.com/jmettraux/rufus-scheduler


1
我已经将rufus用于简单的ruby项目或完整的rails应用程序。
Paulo Fidalgo 2013年

8
您能否更详细地说明“何时”遇到的问题?
公爵

有史以来最好的答案
达伦·迪特里希

17

假设您的任务完成时间不长,只需为每个任务创建一个带有动作的新控制器即可。将任务的逻辑实现为控制器代码,然后在OS级别设置一个cronjob,该任务使用wget调用该控制器的URL,并在适当的时间间隔执行操作。这种方法的优点是:

  1. 就像在普通控制器中一样,具有对所有Rails对象的完全访问权限。
  2. 可以像执行正常操作一样进行开发和测试。
  3. 也可以从一个简单的网页调用您的任务临时任务。
  4. 不要通过启动其他的ruby / rails进程消耗更多的内存。

12
如何防止他人访问此任务?如果任务频繁使用cpu并调用它会导致问题。
sarunw

44
我知道这是前一阵子,但这绝对不再是执行cron工作的最佳方法。当有很多其他访问Rails环境的方法时,为什么要通过Web界面,而违反界面的真正含义呢?
Matchu

6
“假设您的任务不会花费太长时间来完成”的资格似乎是一个巨大的挑战。使用一种更通用的方法会更好,不仅在任务非常快的情况下?这样,您就不会不断地重新评估是否需要使用其他方法来重写此任务。
iconoclast

77
这个老问题是“ rails cron”在google上的最高搜索结果。这个答案远非最佳方法。请参阅其他回复以获得更合理的建议。
Jim Garvin

2
不是最好的方法。您还有许多其他方法可以通过cron作业访问Rails env,而无需调用REST服务。犁耙方法肯定更好
发光

10

脚本/运行程序和rake任务非常适合作为cron作业运行。

这是运行cron作业时必须记住的一件事,非常重要。它们可能不会从您应用的根目录中调用。这意味着您对文件(而不是库)的所有需求都应使用显式路径来完成:例如File.dirname(__ FILE__)+“ / other_file”。这也意味着您必须知道如何从另一个目录中显式调用它们:-)

检查您的代码是否支持从另一个目录运行

# from ~
/path/to/ruby /path/to/app/script/runner -e development "MyClass.class_method"
/path/to/ruby /path/to/rake -f /path/to/app/Rakefile rake:task RAILS_ENV=development

另外,cron作业可能不会像您那样运行,因此,不要依赖于.bashrc中的任何快捷方式。但这只是标准的cron提示;-)


您可以以任何用户身份运行作业(只需为所需的用户设置crontab条目),但是正确的是,配置文件和登录脚本将不会运行,并且您也不会在主目录中启动。因此,通常以“ cd”开头命令,如@ luke-franci的注释所示
Tom Wilson



10

有趣的是,没有人提到Sidetiq。如果您已经在使用Sidekiq,这是一个很好的补充。

Sidetiq提供了一个简单的API,用于为Sidekiq定义循环工作程序。

作业将如下所示:

class MyWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  recurrence { hourly.minute_of_hour(15, 45) }

  def perform
    # do stuff ...
  end
end

8

两者都可以正常工作。我通常使用脚本/运行器。

这是一个例子:

0 6 * * * cd /var/www/apps/your_app/current; ./script/runner --environment production 'EmailSubscription.send_email_subscriptions' >> /var/www/apps/your_app/shared/log/send_email_subscriptions.log 2>&1

如果加载正确的配置文件以连接到数据库,您也可以编写一个纯Ruby脚本来执行此操作。

如果内存是宝贵的,要记住的一件事是脚本/运行程序(或依赖于“环境”的Rake任务)将加载整个Rails环境。如果您只需要在数据库中插入一些记录,则将使用您不需要的内存。如果您编写自己的脚本,则可以避免这种情况。我实际上并不需要这样做,但是我正在考虑。




3

这是我设置我的cron任务的方法。我有一个每天备份SQL数据库(使用rake),另一个每月使缓存过期一次。任何输出都记录在文件log / cron_log中。我的crontab看起来像这样:

crontab -l # command to print all cron tasks
crontab -e # command to edit/add cron tasks

# Contents of crontab
0 1 * * * cd /home/lenart/izziv. whiskas.si/current; /bin/sh cron_tasks >> log/cron_log 2>&1
0 0 1 * * cd /home/lenart/izziv.whiskas.si/current; /usr/bin/env /usr/local/bin/ruby script/runner -e production lib/monthly_cron.rb >> log/cron_log 2>&1

第一个cron任务进行每日数据库备份。cron_tasks的内容如下:

/usr/local/bin/rake db:backup RAILS_ENV=production; date; echo "END OF OUTPUT ----";

第二项任务是稍后设置的,并使用脚本/运行器每月使缓存过期一次(lib / monthly_cron.rb):

#!/usr/local/bin/ruby
# Expire challenge cache
Challenge.force_expire_cache
puts "Expired cache for Challenges (Challenge.force_expire_cache) #{Time.now}"

我想我可以用其他方式备份数据库,但到目前为止它对我有用:)

在不同的服务器上,耙和红宝石的路径可能会有所不同。您可以使用以下方法查看它们的位置:

whereis ruby # -> ruby: /usr/local/bin/ruby
whereis rake # -> rake: /usr/local/bin/rake

3

使用Sidekiq或Resque是更可靠的解决方案。它们都支持重试作业,具有REDIS锁定的排他性,监视和计划。

请记住,Resque是一个死项目(未积极维护),因此Sidekiq是更好的选择。它还具有更高的性能:Sidekiq在单个多线程进程中运行多个工作程序,而Resque在单独的进程中运行每个工作程序。


那是正确的答案。许多可以忘掉很好的特性,即sidekiq或resque被提供,如网络接口,以便监视正在发生的事情:职位数运行,失败或计划,很容易重新启动它们,锁定独特的工人,节流和限制,等等
梅德Polushkin



2

一旦我必须做出相同的决定,今天我对这个决定感到非常满意。使用resque调度程序,因为不仅单独的redis会从数据库中消除负载,而且您还可以访问许多插件,例如resque-web,它提供了出色的用户界面。随着系统的发展,您将要安排越来越多的任务,因此您可以从一个地方进行控制。



1

我使用发条宝石,对我来说效果很好。还有clockworkd一个gem允许脚本作为守护程序运行。


0

我不太确定,我猜这取决于任务:运行频率,需要多少复杂性以及需要与Rails项目直接通信等等。我猜是否只有“一种最佳方法”来做某事,不会有太多不同的方式来做到这一点。

在我的Rails项目的最后工作中,我们需要制作一个批量邀请邮件(调查邀请,而不是垃圾邮件),该邮件应在服务器有时间时发送计划的邮件。我认为我们将使用守护程序工具来运行我创建的rake任务。

不幸的是,我们的公司遇到了一些资金问题,并且被主要竞争对手“收购”,因此该项目从未完成,所以我不知道我们最终会用什么。


0

我使用脚本运行cron,这是运行cron的最佳方法。这是cron的一些示例,

打开CronTab —> sudo crontab -e

并粘贴波纹管线:

00 00 * * * wget https://您的主机/ some_API_end_point

这是一些cron格式,对您有帮助

::CRON FORMAT::

cron格式表

Examples Of crontab Entries
15 6 2 1 * /home/melissa/backup.sh
Run the shell script /home/melissa/backup.sh on January 2 at 6:15 A.M.

15 06 02 Jan * /home/melissa/backup.sh
Same as the above entry. Zeroes can be added at the beginning of a number for legibility, without changing their value.

0 9-18 * * * /home/carl/hourly-archive.sh
Run /home/carl/hourly-archive.sh every hour, on the hour, from 9 A.M. through 6 P.M., every day.

0 9,18 * * Mon /home/wendy/script.sh
Run /home/wendy/script.sh every Monday, at 9 A.M. and 6 P.M.

30 22 * * Mon,Tue,Wed,Thu,Fri /usr/local/bin/backup
Run /usr/local/bin/backup at 10:30 P.M., every weekday. 

希望这能够帮到你 :)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.