Các cách tạo cron jobs trong Ruby On Rails
Mở đầu
Chắc hẳn các các anh em dev đã từng gặp nhiều các vấn đề về tự động update, hay tự động thay đổi trạng thái của object, tự động gửi mail, sao lưu ... Vậy thì sau đây mình xin giới thiệu đến các bạn vài cách để tạo các cron jobs chạy dưới background để thực thi tự động các tiến trình khi lập trình với Ruby On Rails.
Các Gem để hỗ trợ tạo cron jobs cho Rails
Hiện tại đã có rất nhiều Gem hỗ trợ cho việc tạo cron jobs cho Rails, trong bài này mình sẽ giới thiệu 3 Gem phổ biến nhất và 1 cách tạo thủ công. Môi trường là Ubuntu, Centos hoặc Mac OS nhé.
I. Các gem sử dụng trên Sidekiq
Vậy sidekiq là gì thì các bạn tham khảo ở đây nhé, 1 gem rất mạnh dành cho Rails để thực thi các jobs dưới background.
Để sử dụng được sidekiq cũng như các gem được gắn cùng sidekiq thì ta cần đến 1 cache server, ở đây chúng ta sẽ sử dụng redis-server
:
-
để cài đặt redis trên Ubuntu: Tham khảo ở đây
-
để cài đặt redis trên Centos: Tham khảo ở đây
-
để cài đặt redis trên Mac OS: Tham khảo ở đây
-
Trước tiên chúng ta sẽ tạo ra 1 app test:
rails new test-cron-jobs -d mysql cd test-cron-jobs
-
sau đó chúng ta thêm gem ở trong file
Gemfile
... gem 'mysql2', ~> '0.3.21' gem 'sidekiq' ...
rồi chạy bundle install
-
thêm dòng này vào trong
config/routes.rb
:require 'sidekiq/web' resources :users, only: [:show] mount Sidekiq::Web, at: '/sidekiq'
-
cần sửa lại config của file
config/database.yml
để khởi tạo database của app, sau đó chạy các lệnh để tạo ra DBrake db:drop; rake db:create
, tiếp đến tạo bảng User:rails g migration CreateUsers name:string point:integer
-
config sidekiq để sidekiq sẽ chạy trên nền của redis nhé, tạo file
config/initializers/sidekiq.rb
có nội dung:require 'sidekiq' require 'sidekiq/web' Sidekiq.configure_server do |config| config.redis = { url: "redis://localhost:6379/0" } end Sidekiq.configure_client do |config| config.redis = { url: "redis://localhost:6379/0" } end
-
tiếp tục chạy những câu lệnh sau để chạy server:
rake db:migrate # tạo bảo user rails s # chạy server sidekiq # chạy sidekiq
-
sử dụng
rails c
để tạo ra 1 bản ghi user:User.create name: "Jimmy", point: 0
-
Tạo controller/view/model cho bảng user để xem kết quả tự động tăng điểm của user, cứ chuẩn theo bootstrap mà phang, chúng ta sẽ có 1 view về xem điểm của user, 1 view của Sidekiq như thế này:
-
hiện thị thông tin user
-
sidekiq
-
Giờ chúng ta đã có app test cho việc tự động update point của user chạy ngầm dưới background mà ko có tác động của người dùng.
1. Gem Sidetiq
-
thêm gem ở trong file
Gemfile
... gem 'sidekiq' ...
-
tạo ra các file để tự động update point của user
app/workers/auto_update_point_worker.rb
:class AutoUpdatePointWorker include Sidekiq::Worker include Sidetiq::Schedulable recurrence{minutely.second_of_minute((0..59).to_a.select{|v| v % 2 == 0})} # tự động update cứ mỗi 2s def perform User.all.each do |user| user.increment! :point, 10 if user.name == "Jimmy" end end end
-
khởi động lại server & sidekiq, kết quả thu được: (nhớ viết js cho trang hiển thị cứ 2s lại reload để xem kết quả thay đổi tự động, tự động cộng 10 điểm sau mỗi 2s)
Tài liệu tham khảo thêm về gem Sidetiq ở đây nhé! :)
2. Gem Sidekiq Cron
-
thêm trong fiel
Gemfile
... gem 'sidekiq-cron', '~> 0.6.3' ...
-
chạy
bundle install
để cài đặt gem, sau đó tạo 1 fileconfig/schedule.yml
để chứa config sidekiq-cronauto_update_point: cron: * * * * * # cứ 1 phút lại udpate 1 lần class: AutoUpdatePointSidekiqCron # hàm định nghĩa để thực thi
-
tạo file
app/workers/auto_update_price_sidekiq_cron.rb
class AutoUpdatePointSidekiqCron include Sidekiq::Worker def perform User.all.each do |user| user.increment! :point, 10 if user.name == "Jimmy" end end end
-
sửa file
config/initializers/sidekiq.rb
để load cron-jobs khi chạy sidekiq:Sidekiq.configure_server do |config| ... schedule_file = Rails.root.join('config', 'schedule.yml') Sidekiq::Cron::Job.destroy_all! if File.exist?(schedule_file) Sidekiq::Cron::Job.load_from_hash YAML.load(ERB.new(File.read(schedule_file)).result) end end
-
sau đó khởi động lại server và sidekiq và xem kết quả thôi.
Tài liệu tham khảo thêm ở đây nhé.
II. Gem whenever
-
thêm vào file
Gemfile
:... gem 'whenever', :require => false ...
-
chạy
bundle install
để cài đặt gem. sau đó chạywheneverize .
để tạo ra fileconfig/schedule.rb
thêm những dòng sau vào file vừa đc tạo ra:every 1.minutes do runner "AutoUpdatePointWhenever.perform" end
-
tạo ra class
app/workers/auto_udpate_point_whenever.rb
để thực thi hành động auto udpate point cứ sau mỗi 2s được khai báo trong fileschedule.rb
:class AutoUpdatePointWhenever def self.perform User.all.each do |user| user.increment! :point, 10 if user.name == "Jimmy" end end end
-
chạy lệnh
whenever --set 'environment=development'
các bạn sẽ thấy như hình sau thì bạn đã config thành công rồi (ở đây chúng ta sẽ chạy lệnh runner chính là rails runner đó, trên môi trường development). -
chúng ta chạy lệnh
whenever -w --set 'environment=development'
để ghi vào crontab của hệ thống. Sử dụng lệnhcrontab -e
để kiểm tra xem bạn đã ghi thành công hay chưa. nếu thành công hệ thống sẽ tự động udpate point sau mỗi phút -
muốn xoá crontab mà bạn đã ghi vào chỉ cần gõ
whenever -c
Tài liệu tham khảo thêm ở đây nhé.
III. Tạo cron jobs thủ công bằng tay
Như các bạn đã làm ở trên với gem whenever
thì gem này đã đã can thiệp vào crontab của hệ thống và bảo với hệ thống rằng cứ sau mỗi 1 phút sẽ update point.
Vậy tương tự, nếu các bạn không muốn sử dụng Gem whenever
các bạn hoàn toàn có thể tạo cho mình cron jobs tự động execute hàm của Rails. Sau đây là ví dụ, các bạn có thể viết theo như thế này, và tất nhiên rồi crontab của system(ubuntu, centos, macOS) sẽ tự động thực thi cho bạn theo cấu hình mà bạn đặt ra, nhớ config môi trường của rails trong crontab nữa nhé, ở đây mình đang để là development
, nếu các bạn triển khai cho production chỉ cần thay development thành production
là xong
Tài liệu tham khảo về config mốc thời gian tự động thực thi ở đây nhé.
IV. Lời kết
Trên đây mình đã giới thiệu các cách mà các bạn có thể tạo cron jobs cho Rails app. Mong các bạn đóng góp thêm ý kiến ở phía dưới, nếu thích thì like và share cho mọi người khác cùng đọc nhé. Cảm ơn các bạn đã đọc bài của mình. Thank you and see you again!