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 DB rake 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 file config/schedule.yml để chứa config sidekiq-cron

      auto_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ạy wheneverize . để tạo ra file config/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 file schedule.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ệnh crontab -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!