Pekerjaan cron untuk kereta: praktik terbaik?


295

Apa cara terbaik untuk menjalankan tugas yang dijadwalkan di lingkungan Rails? Script / pelari? Menyapu? Saya ingin menjalankan tugas setiap beberapa menit.


149
Bagi mereka yang datang ke sini dari Google, lihat di luar jawaban yang diterima untuk pendekatan yang lebih baik.
jrdioko

4
Jawaban setiap kali tampaknya lebih masuk akal daripada jawaban yang diterima, yang merupakan peretasan lama.
Rob

2
Harap perhatikan juga bahwa setidaknya satu jawaban mengasumsikan Anda memiliki permata tertentu yang terpasang.
Tass

Beberapa (apa yang saya temukan) praktik yang baik dirangkum di sini wisecashhq.com/blog/writing-r reliable
Thibaut Barrère

Dalam banyak kasus, pekerjaan cron berbau buruk. Penjadwal penulisan yang lebih baik melalui sidekiq / resque (atau pekerja latar belakang lainnya), atau menulis daemon (kurang fungsional dan dapat dipantau). Pekerjaan Cron memiliki setidaknya beberapa hal buruk: 1) mengunci untuk satu contoh adalah rasa sakit; 2) pemantauan tidak dapat dilakukan dengan mudah; 3) penanganan pengecualian harus ditulis secara manual lagi; 4) tidak mudah untuk memulai kembali; 5) semua masalah di atas mudah diselesaikan oleh pekerja latar belakang.
Dmitry Polushkin

Jawaban:


110

Saya menggunakan pendekatan rake (didukung oleh heroku )

Dengan file yang disebut lib / tugas / cron.rake ..

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

Untuk mengeksekusi dari baris perintah, ini hanya "rake cron". Perintah ini kemudian dapat diletakkan di sistem operasi cron / task scheduler seperti yang diinginkan.

Perbarui ini pertanyaan dan jawaban yang cukup lama! Beberapa info baru:

  • layanan heroku cron yang saya referensikan telah digantikan oleh Heroku Scheduler
  • untuk tugas yang sering (khususnya di mana Anda ingin menghindari biaya startup lingkungan Rails) pendekatan saya adalah menggunakan cron sistem untuk memanggil skrip yang akan (a) menyodok API webhook yang aman / pribadi untuk menjalankan tugas yang diperlukan di latar belakang atau (b) langsung memberikan tugas pada sistem antrian pilihan Anda

Apa yang seharusnya menjadi entri cron untuk kasus ini, sehingga OS tahu jalan yang benar ke tugas menyapu?
jrdioko

13
NB: hari ini saya menggunakan kapan saja (lihat jawaban Jim Garvin), tetapi entri cron mentah untuk menjalankan tugas menyapu akan menjadi seperti: 30 4 * * * / bin / bash-l -c -c 'cd / opt / railsapp && RAILS_ENV = menyapu produksi cron --silent'
tardate

1
Bagaimana Anda memanggil ini dari konsol? Saya lakukan load "#{Rails.root}/lib/tasks/cron.rake"dan rake cron, tetapi mendapat NameError: variabel lokal tidak terdefinisi atau metode `cron 'untuk main: Object
B Seven

3
Masalah dengan pendekatan ini adalah :environmentketergantungan. Kami memiliki aplikasi Rail yang sangat berat yang membutuhkan waktu lama untuk memulai, Rake kami dipanggil setiap menit dan menghabiskan lebih banyak sumber daya memulai lingkungan Rails yang menjalankan tugas . Saya ingin memiliki lingkungan Rails yang sudah dimulai untuk dipanggil melalui cron, harus ada sesuatu antara pendekatan controller dan lingkungan rake .
fguillen

Berapa lama tugas ini? Saya menggunakan kondisi if. Saya ingin tahu seberapa teratur ini dijalankan. Saya tidak dapat menemukan informasi tentang ini di situs web heroku.
Shubham Chaudhary

254

Saya telah menggunakan Kapanpun sangat populer pada proyek yang sangat bergantung pada tugas yang dijadwalkan, dan itu bagus. Ini memberi Anda DSL yang bagus untuk mendefinisikan tugas terjadwal Anda daripada harus berurusan dengan format crontab. Dari README:

Kapan saja adalah permata Ruby yang menyediakan sintaks yang jelas untuk menulis dan menggunakan pekerjaan cron.

Contoh dari 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

22
Jika dijalankan setiap menit, lingkungan akan dimulai kembali setiap kali, yang bisa mahal. Tampaknya github.com/ssoroka/scheduler_daemon menghindari ini.
lulalala

3
+1 untuk menjaga konfigurasi cron dengan sistem kontrol versi Anda
brittohalloran

3
Saya pikir ini adalah solusi terbaik. Jika Anda menggunakan rel, saya pikir lebih baik menulis semuanya di rails. Dengan pendekatan ini Anda juga bisa melupakan tugas cron saat mengganti server, ia bergerak dengan aplikasi.
Adrian Matteo

Ada Railscast hebat tentang Kapanpun itu benar-benar membantu (versi gratis yang lebih lama juga).
aceofbassgreg

@ Tony, Setiap kali pada dasarnya adalah bahasa khusus domain untuk menulis pekerjaan cron. Ini mengkompilasi ke sintaks cron reguler pada server rails Anda dan cron adalah apa yang mengeksekusi pekerjaan yang Anda tentukan (biasanya melalui rails runner).
Greg

19

Dalam proyek kami, kami pertama kali menggunakan setiap kali permata, tetapi menghadapi beberapa masalah.

Kami kemudian beralih ke permata RUFUS SCHEDULER , yang ternyata sangat mudah dan dapat diandalkan untuk menjadwalkan tugas di Rails.

Kami telah menggunakannya untuk mengirim surat mingguan & harian, dan bahkan untuk menjalankan beberapa tugas menyapu periodik atau metode apa pun.

Kode yang digunakan dalam ini adalah seperti:

    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

Untuk mempelajari lebih lanjut: https://github.com/jmettraux/rufus-scheduler


1
Untuk rufus, seperti yang saya gunakan untuk proyek ruby ​​sederhana atau aplikasi rel penuh.
Paulo Fidalgo

8
Bisakah Anda sedikit lebih spesifik tentang masalah yang Anda hadapi dengan Whenever?
Adipati

jawaban yang paling hebat
Darlan Dieterich

17

Dengan asumsi tugas Anda tidak terlalu lama untuk diselesaikan, cukup buat pengontrol baru dengan aksi untuk setiap tugas. Menerapkan logika tugas sebagai kode pengontrol, Kemudian mengatur tugas cronjob di tingkat OS yang menggunakan wget untuk memohon URL pengontrol ini dan bertindak pada interval waktu yang sesuai. Kelebihan dari metode ini adalah Anda:

  1. Memiliki akses penuh ke semua objek Rails Anda seperti halnya pada pengontrol normal.
  2. Dapat berkembang dan menguji seperti halnya Anda melakukan tindakan normal.
  3. Dapat juga menjalankan tugas Anda adhoc dari halaman web sederhana.
  4. Jangan mengkonsumsi memori lagi dengan menyalakan proses ruby ​​/ rails tambahan.

12
Bagaimana mencegah orang lain mengakses tugas ini? Jika tugas mengambil cpu dan memanggilnya sering akan menimbulkan masalah.
sarunw

44
Saya tahu ini beberapa waktu yang lalu, tapi ini jelas bukan cara terbaik untuk melakukan pekerjaan cron lagi. Mengapa harus melalui antarmuka web, melanggar apa yang benar-benar mewakili antarmuka, ketika ada banyak cara lain untuk mengakses lingkungan Rails?
Matchu

6
Kualifikasi "dengan asumsi tugas Anda tidak perlu waktu terlalu lama untuk selesai" tampaknya seperti BESAR. Bukankah lebih baik menggunakan pendekatan yang lebih bermanfaat secara umum, dan tidak hanya dalam kasus-kasus di mana tugas sangat cepat? Dengan begitu Anda tidak terus-menerus mengevaluasi kembali apakah tugas ini atau itu perlu ditulis ulang menggunakan pendekatan yang berbeda.
iconoclast

77
Pertanyaan lama ini adalah hasil google teratas untuk "rails cron". Jawaban ini jauh dari pendekatan terbaik. Silakan lihat tanggapan lain untuk saran yang lebih waras.
Jim Garvin

2
Bukan cara terbaik. Anda memiliki banyak cara lain untuk mengakses Rails env melalui pekerjaan cron tanpa memanggil layanan REST. Pendekatan Rake tentu saja lebih baik
Shine

10

skrip / pelari dan tugas menyapu sangat baik untuk dijalankan sebagai pekerjaan cron.

Inilah satu hal yang sangat penting yang harus Anda ingat ketika menjalankan pekerjaan cron. Mereka mungkin tidak akan dipanggil dari direktori root aplikasi Anda. Ini berarti semua kebutuhan Anda untuk file (sebagai lawan dari perpustakaan) harus dilakukan dengan jalur eksplisit: mis. File.dirname (__ FILE__) + "/ other_file". Ini juga berarti Anda harus tahu cara memanggil mereka secara eksplisit dari direktori lain :-)

Periksa apakah kode Anda mendukung dijalankan dari direktori lain dengan

# 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

Juga, pekerjaan cron mungkin tidak berjalan seperti Anda, jadi jangan bergantung pada pintasan apa pun yang Anda masukkan .bashrc. Tapi itu hanya tip cron standar ;-)


Anda dapat menjalankan pekerjaan sebagai pengguna mana pun (cukup setel entri crontab untuk pengguna yang Anda inginkan) tetapi Anda benar bahwa skrip profil dan login tidak akan berjalan dan Anda tidak akan mulai di direktori home Anda. Jadi itu biasa untuk memulai perintah dengan "cd" seperti yang ditunjukkan dalam komentar @ luke-franci
Tom Wilson

10

Masalah dengan kapan saja (dan cron) adalah bahwa reload lingkungan rel setiap kali dieksekusi, yang merupakan masalah nyata ketika tugas Anda sering atau memiliki banyak pekerjaan inisialisasi yang harus dilakukan. Saya punya masalah dalam produksi karena ini dan harus memperingatkan Anda.

Penjadwal Rufus melakukannya untuk saya ( https://github.com/jmettraux/rufus-scheduler )

Ketika saya memiliki pekerjaan yang panjang untuk dijalankan, saya menggunakannya dengan menunda_job ( https://github.com/collectiveidea/delayed_job )

Saya harap ini membantu!


10

Saya penggemar berat resque / scheduler resque . Anda tidak hanya dapat menjalankan tugas yang mirip cron tetapi juga tugas pada waktu tertentu. Kelemahannya, ini membutuhkan server Redis.


10

Yang menarik tidak ada yang menyebut Sidetiq . Ini adalah tambahan yang bagus jika Anda sudah menggunakan Sidekiq.

Sidetiq menyediakan API sederhana untuk mendefinisikan pekerja berulang untuk Sidekiq.

Pekerjaan akan terlihat seperti ini:

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

  recurrence { hourly.minute_of_hour(15, 45) }

  def perform
    # do stuff ...
  end
end

8

Keduanya akan bekerja dengan baik. Saya biasanya menggunakan script / runner.

Ini sebuah contoh:

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

Anda juga dapat menulis skrip Ruby murni untuk melakukan ini jika Anda memuat file konfigurasi yang tepat untuk terhubung ke database Anda.

Satu hal yang perlu diingat jika memori berharga adalah bahwa skrip / pelari (atau tugas Rake yang bergantung pada 'lingkungan') akan memuat seluruh lingkungan Rails. Jika Anda hanya perlu memasukkan beberapa catatan ke dalam basis data, ini akan menggunakan memori yang tidak harus Anda miliki. Jika Anda menulis skrip Anda sendiri, Anda dapat menghindari ini. Saya belum benar-benar perlu melakukan ini, tetapi saya sedang mempertimbangkannya.


8

Gunakan Craken (pekerjaan cron centric cron)


1
menulis pekerjaan cron sangat sulit, lebih baik mengunduh permata untuk itu
f0ster

1
itu tidak sulit - tetapi memiliki mereka disimpan di git dan selalu up to date di deploy adalah nilai tambah yang besar ketika seseorang bekerja dalam sebuah tim.
Thibaut Barrère


3

Inilah cara saya mengatur tugas cron saya. Saya punya satu untuk membuat cadangan harian dari database SQL (menggunakan menyapu) dan yang lain untuk berakhir cache sekali sebulan. Output apa pun dicatat dalam log file / cron_log. Crontab saya terlihat seperti ini:

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

Tugas cron pertama membuat backup db harian. Isi cron_tasks adalah sebagai berikut:

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

Tugas kedua adalah setup kemudian dan menggunakan script / runner untuk kedaluwarsa cache sebulan sekali (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}"

Saya kira saya bisa membuat cadangan basis data dengan cara lain tetapi sejauh ini berfungsi untuk saya :)

The jalur untuk meraup dan ruby dapat bervariasi pada server yang berbeda. Anda dapat melihat di mana mereka berada dengan menggunakan:

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

3

Menggunakan sesuatu Sidekiq atau Resque adalah solusi yang jauh lebih kuat. Keduanya mendukung pengerjaan ulang pekerjaan, eksklusivitas dengan kunci REDIS, pemantauan, dan penjadwalan.

Perlu diingat bahwa Resque adalah proyek mati (tidak dipelihara secara aktif), jadi Sidekiq adalah alternatif yang jauh lebih baik. Ini juga lebih performant: Sidekiq menjalankan beberapa pekerja pada satu proses, multithread sementara Resque menjalankan setiap pekerja dalam proses terpisah.


Itu jawaban yang benar. Banyak yang bisa melupakan fitur-fitur bagus, yang disediakan oleh sidekiq atau resque, seperti antarmuka web untuk memantau apa yang terjadi: jumlah pekerjaan yang berjalan, gagal atau dijadwalkan, mulai kembali dengan mudah, kunci untuk pekerja yang unik, pembatasan dan pembatasan, dll.
Dmitry Polushkin

3

Saya baru-baru ini menciptakan beberapa pekerjaan cron untuk proyek yang telah saya kerjakan.

Saya menemukan bahwa Clockwork permata sangat berguna.

require 'clockwork'

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

Anda bahkan dapat menjadwalkan pekerjaan latar belakang Anda menggunakan permata ini. Untuk dokumentasi dan bantuan lebih lanjut lihat https://github.com/Rykian/clockwork



2

Pernah saya harus membuat keputusan yang sama dan saya sangat senang dengan keputusan itu hari ini. Gunakan penjadwal ulang karena tidak hanya redis yang terpisah akan mengeluarkan beban dari db Anda, Anda juga akan memiliki akses ke banyak plugin seperti resque-web yang menyediakan antarmuka pengguna yang hebat. Ketika sistem Anda berkembang, Anda akan memiliki lebih banyak tugas yang dijadwalkan sehingga Anda dapat mengendalikannya dari satu tempat.


1

Mungkin cara terbaik untuk melakukannya adalah menggunakan rake untuk menulis tugas yang Anda butuhkan dan jalankan saja melalui baris perintah.

Anda dapat melihat video yang sangat membantu di railscasts

Lihat juga sumber daya lain ini:


Saya mencoba gagal menggunakan sintaks dalam tutorial ini. Tugas tidak dijalankan.
Tass

1

Saya menggunakan permata jarum jam dan itu bekerja cukup baik untuk saya. Ada juga clockworkdpermata yang memungkinkan skrip dijalankan sebagai daemon.


0

Saya tidak begitu yakin, saya kira itu tergantung pada tugas: seberapa sering menjalankan, seberapa rumit dan seberapa banyak komunikasi langsung dengan proyek kereta diperlukan dll. Saya kira jika hanya ada "Satu Cara Terbaik" untuk melakukan sesuatu , tidak akan ada begitu banyak cara untuk melakukannya.

Pada pekerjaan terakhir saya di proyek Rails, kami perlu membuat mailer undangan batch (undangan survei, bukan spam) yang akan mengirim email yang direncanakan kapan pun server punya waktu. Saya pikir kami akan menggunakan alat daemon untuk menjalankan tugas menyapu yang telah saya buat.

Sayangnya, perusahaan kami memiliki beberapa masalah uang dan "dibeli" oleh saingan utama sehingga proyek itu tidak pernah selesai, jadi saya tidak tahu apa yang akhirnya akan kami gunakan.


0

Saya Menggunakan skrip untuk menjalankan cron, itu adalah cara terbaik untuk menjalankan cron. Berikut ini beberapa contoh untuk cron,

Buka CronTab -> sudo crontab -e

Dan tempelkan garis di bawah:

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

Berikut ini beberapa format cron, akan membantu Anda

::CRON FORMAT::

tabel 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. 

Semoga ini bisa membantu Anda :)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.