Raylar için bir cron işi: en iyi uygulamalar?


295

Rails ortamında zamanlanmış görevleri çalıştırmanın en iyi yolu nedir? Senaryo / koşucu? Tırmık? Görevi birkaç dakikada bir çalıştırmak istiyorum.


149
Buraya Google'dan gelenler için, daha iyi yaklaşımlar için kabul edilen cevabın ötesine bakın.
jrdioko

4
Ne zaman cevap, eski bir hack olan kabul edilen cevaptan daha makul görünüyor.
Rob

2
Lütfen en az bir cevabın belirli bir cevher yüklü olduğunu varsaydığını da unutmayın.
Tass

Birkaç (iyi bulduğum) iyi uygulama burada özetlenmiştir wisecashhq.com/blog/writing-reliable-cron-jobs
Thibaut Barrère

Birçok durumda cron işleri kötü bir kokudur. Zamanlayıcıyı sidekiq / resque (veya başka bir arka plan çalışanı) aracılığıyla daha iyi yazın veya bir arka plan programı (daha az işlevsel ve izlenebilir) yazın. Cron işlerinde en az birkaç kötü şey vardır: 1) bir örnek için kilitleme bir acıdır; 2) izleme kolayca yapılamaz; 3) istisnaların ele alınması tekrar elle yazılmalıdır; 4) yeniden başlatmak kolay değil; 5) yukarıdaki tüm konular kolayca arka plan çalışanları tarafından çözme.
Dmitry Polushkin

Yanıtlar:


110

Komisyon yaklaşımını kullanıyorum ( heroku tarafından desteklendiği gibi )

Lib / tasklar / cron.rake adlı bir dosya ile ..

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

Komut satırından yürütmek için bu sadece "komisyon cron". Bu komut daha sonra istendiği gibi işletim sistemi cron / görev zamanlayıcısına konabilir.

Güncelleme bu oldukça eski bir soru ve cevap! Bazı yeni bilgiler:

  • referans verdiğim heroku cron servisinin yerini Heroku Scheduler aldı
  • sık görevler için (özellikle Rails ortam başlangıç ​​maliyetinden kaçınmak istediğiniz yer) benim tercih ettiğim yaklaşım, (a) arka planda gerekli görevi başlatmak için güvenli / özel bir webhook API'sini çağıracak bir komut dosyasını çağırmak için sistem cronunu kullanmaktır. veya (b) seçtiğiniz kuyruğa alma sisteminizdeki bir görevi doğrudan enqueque edin

Bu durumda cron girişi ne olmalı, bu yüzden işletim sistemi komisyon görevine doğru yolu biliyor mu?
jrdioko

13
Not: Bu günlerde ne zaman kullanıyorum (Jim Garvin'in cevabına bakın), ancak komisyon görevini çalıştırmak için ham bir cron girişi şuna benzer: 30 4 * * * / bin / bash -l -c 'cd / opt / railsapp && RAILS_ENV = üretim tırmığı cron --silent '
tardate

1
Bunu konsoldan nasıl çağırıyorsunuz? Ben yaptım load "#{Rails.root}/lib/tasks/cron.rake"ve rake cronfakat NameError var: tanımsız yerel değişken ya da ana yöntemi `cron'u': Nesne
B Yedi

3
Bu yaklaşımdaki sorun :environmentbağımlılıktır. Başlaması uzun süren çok ağır bir Rails uygulamamız var, Komisyonumuz her dakika çağrılıyor ve görevi yerine getiren Rails ortamını başlatan daha fazla kaynak tüketiyor . Daha önce başlatılmış bir Rails ortamının cron üzerinden çağrılmasını isterdim , kontrolör yaklaşımı ve tırmık ortamı arasında bir şey olmalı .
fguillen

Bu görevin süresi nedir? Bir if koşulu kullanıyorum. Bunun ne kadar düzenli yürütüldüğünü bilmek istiyorum. Bununla ilgili hiçbir bilgiyi heroku web sitesinde bulamıyorum.
Shubham Chaudhary

254

Ben son derece popüler kullandım ne zaman zamanlanmış görevler temeline dayanmaktadır üzerinde projeler ve bu harika. Crontab formatıyla uğraşmak yerine zamanlanmış görevlerinizi tanımlamanız için size güzel bir DSL sunar. README'den:

Cron işlerini yazmak ve dağıtmak için açık bir sözdizimi sağlayan bir Ruby taşı olduğunda.

README'den bir örnek:

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
Her dakika çalıştırılırsa, ortam her seferinde yeniden başlatılır, bu da maliyetli olabilir. Görünüşe göre github.com/ssoroka/scheduler_daemon bundan kaçınıyor.
lulalala

3
Sürüm kontrol sisteminizle cron yapılandırmasını korumak için +1
brittohalloran

3
Bence bu en iyi çözüm. Raylar kullanıyorsanız, her şeyi raylara yazmak daha iyi olur. Bu yaklaşımla, sunucuları değiştirirken cron görevini de unutabilirsiniz, uygulama ile birlikte hareket eder.
Adrian Matteo

Ne zaman gerçekten yararlı (hakkında eski bir ücretsiz sürümü de var) hakkında büyük bir Railscast var.
aceofbassgreg

@Tony, Temelde cron işleri yazmak için alana özgü bir dil olduğunda. Rails sunucunuzda düzenli cron sözdizimi olarak derlenir ve cron belirttiğiniz işleri yürütür (genellikle rails runner aracılığıyla).
Greg

19

Projemizde ilk kez mücevher kullandığımız halde bazı sorunlarla karşılaştık.

Daha sonra RUFUS SCHEDULER gemine geçtik, bu da Rails'teki görevleri zamanlamak için çok kolay ve güvenilir olduğu ortaya çıktı.

Haftalık ve günlük posta göndermek ve hatta periyodik komisyon görevleri veya herhangi bir yöntem yürütmek için kullandık.

Burada kullanılan kod şöyledir:

    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

Daha fazla bilgi edinmek için: https://github.com/jmettraux/rufus-scheduler


1
Hem basit yakut projeleri hem de tam ray uygulamaları için kullandığım için rufus için hazır.
Paulo Fidalgo

8
Ne Zaman Karşılaştığınız Sorunlar Hakkında Biraz Daha Açık Olabilir misiniz?
Duke

en büyük cevap
Darlan Dieterich

17

Görevlerinizin tamamlanması çok uzun sürmüyorsa, her görev için bir eylem içeren yeni bir denetleyici oluşturun. Görevin mantığını denetleyici kodu olarak uygulayın, Daha sonra bu denetleyicinin URL'sini ve eylemi uygun zaman aralıklarında çağırmak için wget kullanan işletim sistemi düzeyinde bir cronjob oluşturun. Bu yöntemin avantajları:

  1. Normal bir denetleyicide olduğu gibi tüm Rails nesnelerinize tam erişime sahip olun.
  2. Tıpkı normal eylemler gibi geliştirebilir ve test edebilirsiniz.
  3. Ayrıca basit bir web sayfasından adhoc görevlerinizi çağırabilir.
  4. Ek yakut / ray süreçlerini ateşleyerek daha fazla bellek tüketmeyin.

12
Başkalarının bu göreve erişmesini nasıl önleyebilirim? Görev cpu alıp sık sık çağırırsa sorunlara neden olur.
sarunw

44
Bunun bir süre önce olduğunu biliyorum, ama bu kesinlikle cron işleri yapmanın en iyi yolu değil. Rails ortamına erişmenin başka yolları olduğunda neden web arayüzünden geçerek arayüzün gerçekte neyi temsil ettiğini ihlal ediyorsunuz?
Kasım'da Matchu

6
"Görevlerinizin tamamlanması çok uzun sürmediğini varsaymak" yeterliliği BÜYÜK bir görev gibi görünüyor. Yalnızca görevlerin çok hızlı olduğu durumlarda değil, daha genel olarak kullanışlı bir yaklaşım kullanmak daha iyi olmaz mıydı? Bu şekilde, bu veya bu görevin farklı bir yaklaşımla yeniden yazılması gerekip gerekmediğini sürekli olarak yeniden değerlendirmezsiniz.
iconoclast

77
Bu eski soru "rails cron" için en iyi google sonucudur. Bu cevap en iyi yaklaşımdan uzaktır. Daha akılcı öneriler için lütfen diğer yanıtlara bakın.
Jim Garvin

2
En iyi yol değil. Bir REST hizmetini aramadan bir cron işi aracılığıyla Rails env'ye erişmenin birçok yolu var. Komisyon yaklaşımı kesinlikle daha iyi
Shine

10

script / runner ve rake görevleri cron işleri olarak çalışmak için mükemmeldir.

İşte cron işlerini çalıştırırken hatırlamanız gereken çok önemli bir şey. Muhtemelen uygulamanızın kök dizininden çağrılmazlar. Bu, dosyalara (kitaplıkların aksine) ilişkin tüm gereksinimlerinizin açık yolla yapılması gerektiği anlamına gelir: örn. File.dirname (__ FILE__) + "/ other_file". Bu aynı zamanda onları başka bir dizinden nasıl açıkça arayacağınızı bilmeniz gerektiği anlamına gelir :-)

Kodunuzun başka bir dizinden çalıştırılmasını destekleyip desteklemediğini kontrol edin

# 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

Ayrıca, cron işleri muhtemelen sizin gibi çalışmaz, bu nedenle .bashrc'ye koyduğunuz herhangi bir kısayola güvenmeyin. Ama bu sadece standart bir cron ipucu ;-)


İşi herhangi bir kullanıcı olarak çalıştırabilirsiniz (sadece istediğiniz kullanıcı için crontab girişini ayarlayın), ancak profil ve oturum açma komut dosyalarının çalışmayacağı ve ana dizininizde başlamayacaksınız. Komutu @ luke-franci'nin yorumunda gösterildiği gibi "cd" ile başlatmak yaygındır
Tom Wilson

10

Her zaman (ve cron) ile ilgili sorun, her yürütüldüğünde raylar ortamını yeniden yüklemesidir, bu da görevleriniz sık olduğunda veya çok fazla başlatma işi olduğunda gerçek bir sorundur. Bu yüzden üretimde sorunlar yaşadım ve sizi uyarmalıyım.

Rufus zamanlayıcı bunu benim için yapıyor ( https://github.com/jmettraux/rufus-scheduler )

Çalışacak uzun işlerim olduğunda, gecikmeli_job ile kullanıyorum ( https://github.com/collectiveidea/delayed_job )

Umarım bu yardımcı olur!


10

Resque / resque scheduler hayranıyım . Yalnızca yinelenen cron benzeri görevleri değil, belirli zamanlarda görevleri de çalıştırabilirsiniz. Dezavantajı, bir Redis sunucusu gerektirir.


10

Hiç kimse Sidetiq'ten bahsetmedi . Zaten Sidekiq kullanıyorsanız güzel bir ektir.

Sidetiq, Sidekiq için yinelenen çalışanları tanımlamak için basit bir API sağlar.

İş şu şekilde görünecektir:

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

  recurrence { hourly.minute_of_hour(15, 45) }

  def perform
    # do stuff ...
  end
end

8

Her ikisi de iyi çalışır. Genellikle script / runner kullanıyorum.

İşte bir örnek:

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

Veritabanınıza bağlanmak için doğru yapılandırma dosyalarını yüklerseniz, bunu yapmak için salt Ruby komut dosyası da yazabilirsiniz.

Bellek değerliyse akılda tutulması gereken bir şey, komut dosyasının / koşucunun (veya 'ortama bağlı bir Komisyon görevinin) tüm Rails ortamını yükleyeceğidir. Veritabanına yalnızca bazı kayıtlar eklemeniz gerekiyorsa, bu gerçekten gerekli olmayan belleği kullanır. Kendi komut dosyanızı yazarsanız, bundan kaçınabilirsiniz. Bunu henüz yapmam gerekmiyordu, ama bunu düşünüyorum.


8

Craken kullanın (tırmık merkezli cron işleri)


1
cron işleri yazmak çok zor, daha iyi bunun için bir mücevher indir
f0ster

1
zor değil - ama bir ekipte çalıştığında git'te depolanmaları ve her zaman güncel durumda olmaları büyük bir artı.
Thibaut Barrère


3

İşte cron görevlerimi nasıl ayarladım. Ben bir SQL veritabanı günlük komisyon yapmak (komisyon kullanarak) ve başka bir ayda bir kez önbellek süresi var. Çıktılar bir dosya günlüğüne / cron_log dosyasına kaydedilir. Crontab'ım şöyle:

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

İlk cron görevi günlük db yedeklemeleri yapar. Cron_tasks içeriği aşağıdaki gibidir:

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

İkinci görev daha sonra ayarlandı ve önbelleği ayda bir kez sona erdirmek için script / runner kullanıyor (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}"

Ben başka bir şekilde veritabanı yedekleme olabilir sanırım ama şimdiye kadar benim için çalışıyor :)

Yolları komisyon, yakut farklı sunucularda değişebilir. Nerede olduklarını kullanarak şunları görebilirsiniz:

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

3

Bir şey Sidekiq veya Resque kullanmak çok daha sağlam bir çözümdür. Her ikisi de yeniden deneme işlerini, REDIS kilidi ile ayrıcalığı, izleme ve zamanlamayı destekler.

Resque'un ölü bir proje (aktif olarak korunmayan) olduğunu unutmayın, bu nedenle Sidekiq daha iyi bir alternatiftir. Ayrıca daha performanslıdır: Sidekiq birkaç işçiyi tek ve çok iş parçacıklı bir işlemde çalıştırırken Resque her işçiyi ayrı bir işlemde çalıştırır.


Bu doğru bir cevap. Birçoğu, neler olup bittiğini izlemek için web arayüzü gibi, sidekiq veya resque'nin sağladığı güzel özellikleri unutabilir: çalışan, başarısız veya planlanan işlerin sayısı, kolayca yeniden başlatın, benzersiz çalışanlar için kilitleyin, azaltma ve sınırlama, vb.
Dmitry Bölüm Polushkin

3

Son zamanlarda üzerinde çalıştığım projeler için bazı cron işleri yarattım.

Gem Clockwork çok yararlı buldum .

require 'clockwork'

module Clockwork
  every(10.seconds, 'frequent.job')
end

Hatta bu taş kullanarak arka plan iş planlayabilirsiniz. Dokümantasyon ve daha fazla yardım için https://github.com/Rykian/clockwork adresine bakın.



2

Bir keresinde aynı kararı vermek zorunda kaldım ve bugün bu karardan gerçekten memnunum. Resque zamanlayıcı kullanın, çünkü sadece ayrı bir redis yükü db'nizden çıkarmaz, aynı zamanda mükemmel bir kullanıcı arayüzü sağlayan resque-web gibi birçok eklentiye de erişebilirsiniz. Sisteminiz geliştikçe, zamanlamak için daha fazla göreve sahip olacaksınız, böylece onları tek bir yerden kontrol edebileceksiniz.



1

Clockwork mücevher kullandım ve benim için oldukça iyi çalışıyor. clockworkdBir betiğin bir daemon olarak çalışmasına izin veren mücevher de vardır .


0

Gerçekten emin değilim, sanırım göreve göre değişir: ne sıklıkta çalıştırılacağı, ne kadar karmaşık ve raylar projesi ile ne kadar doğrudan iletişim gerekli vb. Sanırım bir şey yapmak için sadece "Tek En İyi Yol" , bunu yapmanın pek çok farklı yolu olmazdı.

Bir Rails projesindeki son işimde, sunucunun zamanı olduğunda planlanan postaları göndermesi gereken bir toplu davet postası (anket davetiyeleri, spam değil) yapmamız gerekiyordu. Sanırım yarattığım tırmıklama görevlerini yürütmek için daemon araçlarını kullanacağız .

Ne yazık ki, şirketimizin bazı para sorunları vardı ve ana rakip tarafından "satın alındı" böylece proje asla tamamlanmadı, bu yüzden sonunda ne kullanacağımızı bilmiyorum.


0

Ben cron çalıştırmak için komut dosyası kullanın, bu bir cron çalıştırmak için en iyi yoldur. İşte cron için bir örnek,

CronTab'ı açın -> sudo crontab -e

Ve Körük çizgilerini yapıştırın:

00 00 * * * wget https: // your_host / some_API_end_point

İşte bazı cron formatı, size yardımcı olacak

::CRON FORMAT::

cron format tablosu

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. 

Bu size yardımcı olacağını umuyoruz :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.