Rails 的 cron 作业:最佳实践?
-
08-07-2019 - |
题
在 Rails 环境中运行计划任务的最佳方式是什么?脚本/运行程序?耙?
解决方案
我正在使用耙子方法(由 赫罗库)
使用名为 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格式。来自自述文件:
每当Ruby gem提供一个 清晰的编写和部署语法 cron jobs。
自述文件中的示例:
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
在我们的项目中,我们首先使用gem,但遇到了一些问题。
然后我们切换到 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
假设您的任务完成时间不长,只需创建一个新控制器,并为每个任务执行操作。将任务的逻辑实现为控制器代码,然后在操作系统级别设置一个cronjob,使用wget以适当的时间间隔调用此控制器的URL和操作。这种方法的优点是:
- 完全访问所有Rails对象,就像在普通控制器中一样。
- 可以像正常行动一样进行开发和测试。
- 还可以从简单的网页调用您的任务。
- 不要通过启动其他ruby / rails进程来消耗更多内存。 醇>
每当(和cron)的问题在于每次执行时都会重新加载rails环境,这在您的任务频繁或需要进行大量初始化工作时才是真正的问题。因此我在生产中遇到了问题,必须警告你。
Rufus调度程序为我做( https://github.com/jmettraux/rufus-scheduler )
当我有很长的工作要运行时,我将它与delayed_job一起使用( https://github.com/collectiveidea/delayed_job )
我希望这有帮助!
我是 resque / resque scheduler 。您不仅可以在特定时间运行重复的类似cron的任务,还可以运行任务。缺点是,它需要Redis服务器。
脚本/跑步者和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 jobs可能不会像你一样运行,所以不要依赖你放入.bashrc的任何快捷方式。但这只是一个标准的cron提示; - )
有趣的是,没有人提到 Sidetiq 。 如果您已经使用Sidekiq,这是很好的补充。
Sidetiq提供了一个简单的API来定义重复工作者 Sidekiq。
Job将如下所示:
class MyWorker
include Sidekiq::Worker
include Sidetiq::Schedulable
recurrence { hourly.minute_of_hour(15, 45) }
def perform
# do stuff ...
end
end
两者都可以正常工作。我通常使用脚本/跑步者。
以下是一个例子:
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 centric cron jobs)
以下是我如何设置我的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 ----";
第二个任务是稍后设置的,并使用script / runner每月一次到期缓存(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
使用Sidekiq或Resque是一种更强大的解决方案。它们都支持重试作业,具有REDIS锁定的排他性,监控和日程安排。
请记住,Resque是一个死的项目(没有积极维护),所以Sidekiq是一种更好的选择。它的性能也更高:Sidekiq在单个多线程进程中运行多个worker,而Resque在一个单独的进程中运行每个worker。
我最近为我一直在做的项目创建了一些cron作业。
我发现宝石发条非常有用。
require 'clockwork'
module Clockwork
every(10.seconds, 'frequent.job')
end
您甚至可以使用此gem安排后台工作。 有关文档和进一步帮助,请参阅 https://github.com/Rykian/clockwork
一旦我做出同样的决定,我今天对这个决定感到非常满意。使用 resque scheduler ,因为不仅单独的redis将从您的数据库中取出负载,您还可以访问许多插件,如resque-web,它提供了一个出色的用户界面。随着系统的发展,您将有越来越多的任务要安排,这样您就可以从一个地方控制它们。
你可以使用resque和resque-shheduler gem来创建crons,这很容易做到。
我使用发条宝石,它对我来说效果很好。还有 clockworkd
gem,允许脚本作为守护进程运行。
我不太确定,我想这取决于任务:运行的频率,复杂程度以及与rails项目的直接通信需要多少等等。我猜是否只有"一个最好的方式“做某事,没有那么多不同的方法去做。
在Rails项目的最后一份工作中,我们需要制作批量邀请邮件(调查邀请,而不是垃圾邮件),只要服务器有时间,就应该发送计划邮件。我想我们将使用守护进程工具来运行我创建的rake任务。
不幸的是,我们公司遇到了一些资金问题并被“买走”了。由主要竞争对手所以项目从未完成,所以我不知道我们最终会使用什么。
我使用脚本运行cron,这是运行cron的最佳方式。 以下是cron的一些示例,
打开CronTab—> sudo crontab -e
并粘贴Bellow线:
00 00 * * * wget https:// your_host / some_API_end_point
这是一些cron格式,会帮助你
::CRON FORMAT::
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.
希望这会对你有所帮助:)。