rails的cron工作:最佳实践?

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

117198 次浏览

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

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

我使用backgrounddrb。

http://backgroundrb.rubyforge.org/

我用它来运行预定的任务以及对于正常的客户机/服务器关系花费太长时间的任务。

我不太确定,我猜这取决于任务:多长时间运行一次,有多复杂,需要与rails项目进行多少直接交流等等。我想如果只有“一个最好的方法”来做某事,就不会有这么多不同的方法来做它。

在我在Rails项目中的上一份工作中,我们需要制作一个批量邀请邮件(调查邀请,而不是垃圾邮件),它应该在服务器有时间的时候发送计划好的邮件。我认为我们将使用虚拟光驱来运行我创建的rake任务。

不幸的是,我们公司遇到了一些资金问题,被主要竞争对手“收购”了,所以这个项目一直没有完成,所以我不知道我们最终会用什么。

Script /runner和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提示;-)

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

这里有一个例子:

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环境。如果您只需要向数据库中插入一些记录,这将使用您实际上不必使用的内存。如果您编写自己的脚本,则可以避免这种情况。实际上我还没有必要这么做,但我正在考虑。

使用Craken (rake中心cron作业)

下面是我如何设置我的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}"

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

rake和ruby的路径在不同的服务器上可能不同。你可以使用以下命令查看它们的位置:

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

我使用rake方法(由heroku支持)

使用名为lib/tasks/cron的文件。rake . .

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

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

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

  • 我引用的heroku cron服务已被Heroku调度器取代
  • 对于频繁的任务(特别是当你想避免Rails环境启动成本时),我的首选方法是使用系统cron来调用一个脚本,该脚本将(a)戳一个安全/私有webhook API来在后台调用所需的任务,或者(b)直接在你选择的排队系统上排队任务

我在严重依赖计划任务的项目中使用了非常流行的每当,它很棒。它为您提供了一个很好的DSL来定义计划任务,而不必处理crontab格式。自述:

Whenever是一个Ruby宝石,提供了一个 用于编写和部署的清晰语法 cron作业。< / p >

来自README的例子:

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

最好的方法可能是使用rake来编写所需的任务,然后通过命令行执行它。

你可以看到一个非常有用的铁路广播的视频

也可以看看其他资源:

无论何时(和cron)的问题是,它每次执行时都会重新加载rails环境,当任务频繁或有大量初始化工作要做时,这是一个真正的问题。由于这个原因,我在生产中出现了问题,必须警告你。

Rufus调度器为我做(https://github.com/jmettraux/rufus-scheduler)

当我有较长的作业要运行时,我使用delayed_job (https://github.com/collectiveidea/delayed_job)

我希望这能有所帮助!

我是resque/resque调度器的忠实粉丝。您不仅可以重复运行类似cron的任务,还可以在特定时间运行任务。缺点是,它需要一个Redis服务器。

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

然后我们切换到RUFUS SCHEDULER . gem,它被证明在Rails中调度任务非常容易和可靠。

我们用它来发送每周&每日邮件,甚至运行一些定期耙任务或任何方法。

这里使用的代码是这样的:

    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

我曾经也做过同样的决定,今天我对这个决定很满意。使用resque调度器,因为不仅一个单独的redis将从你的db中取出负载,你还可以访问许多插件,如resque-web,它提供了一个很棒的用户界面。随着系统的发展,你会有越来越多的任务要安排,这样你就可以从一个地方控制它们。

我使用发条宝石,它为我工作得很好。还有clockworkd gem允许脚本作为守护进程运行。

你可以使用resqueresque-schedular gem来创建cron,这很容易做到。

https://github.com/resque/resque

https://github.com/resque/resque-scheduler

使用Sidekiq或Resque是一种更加健壮的解决方案。它们都支持重试作业、使用REDIS锁的排他性、监控和调度。

请记住,Resque是一个死项目(没有积极维护),所以Sidekiq是一个更好的选择。它的性能也更高:Sidekiq在单个多线程进程上运行多个worker,而Resque在单独的进程中运行每个worker。

有趣的是没有人提到Sidetiq。 如果你已经在使用Sidekiq,这是一个很好的补充
Sidetiq提供了一个简单的API,用于定义循环工作者 Sidekiq . < / p >

Job看起来是这样的:

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


recurrence { hourly.minute_of_hour(15, 45) }


def perform
# do stuff ...
end
end

我最近为我一直在做的项目创建了一些cron作业。

我发现宝石发条非常有用。

require 'clockwork'


module Clockwork
every(10.seconds, 'frequent.job')
end
你甚至可以使用这个gem来安排你的后台任务。 有关文档和进一步帮助,请参阅https://github.com/Rykian/clockwork

I使用脚本运行cron,这是运行cron的最好方式。 下面是cron的一些例子,

打开CronTab - > sudo CronTab -e

并粘贴波纹线:

00 00 * * wget https://your_host/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.

希望这对你有帮助:)