Thinking about Cron and Clockwork

Tổng quan

Cron là một tiện ích cho phép thực hiện các tác vụ một cách tự động theo định kỳ ở chế độ nền của hệ thống. Crontab là một file chứa đựng các schedules của các tasks được chạy.

Ví dụ có một ứng dụng cho phép người dùng xem thông tin, chúng ta cần một cronjob để lấy thông tin cập nhật mỗi giờ và một cronjob khác để xóa bỏ những tin đã đọc vào mỗi buổi tối hay một ứng dụng thường gặp nhất là gửi email định kỳ cho khách hàng, gửi thông báo, báo giá vào các khung giờ xác định chẳng hạn.

Cách sử dụng

    every 1.day, :at => '6:30 am' do
      runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
    end

Nhược điểm của Cron

  1. Debug khó: Các câu lệnh thực thi của cron khá vắn tắt, điều này khiến bạn có thể nhầm lẫn trong việc lập lịch. Thiếu thông tin phản hồi sẽ gây ra việc khó chẩn đoán lỗi.
  2. Trong trường hợp ứng dụng chạy trên nhiều servers khác nhau, ta cần locks để lưu trữ và đánh dấu những vùng được chia sẻ (database or memcache) để tránh việc lặp lại schedules. Tuy nhiên đôi lúc xảy ra lỗi như cronjob bị thoát bất thường hay vòng lặp vô hạn sẽ khiến mọi việc trở nên phức tạp.

Chính vì điều này chúng ta không thể chỉ xử dụng mỗi cron cho việc lên schedule jobs. Cần một công cụ hỗ trợ khác hữu hiệu hơn. Cụ thể là

  • Cú pháp mạch lạc và dễ dùng.
  • Dễ dàng test.
  • Không có nhiều khác biệt giữa môi trường tạo schedule và môi trường test.
  • Khuyến khích việc sử dụng một hệ thống xử lý hàng đợi hơn là làm trực tiếp trong schedule.
  • Chạy nhiêu servers mà không lo lắng việc lặp lại chedules Clockwork là một công cụ như vậy.

Cài đặt và sử dụng Clockwork

    gem 'clockwork', require: false

Tạo jobs với clockwork - clock.rb

      require 'clockwork'
      include Clockwork

      handler do |job|
        puts "Running #{job}"
      end

      every(10.seconds, 'frequent.job')
      every(3.minutes, 'less.frequent.job')
      every(1.hour, 'hourly.job')

       every(1.day, 'midnight.job', :at => '00:00')

Tên job và thời gian thực thi là 2 thông số bắt buộc. Bạn có thể tùy chọn thiết lập giờ, phút, giây cho việc chạy schedule. Job được chuyển tới hệ thống sắp xếp hàng đợi để chờ thực thi. Để hiểu hơn về schedule parameters trên clockwork bạn có thể tìm trên parameters section of the clockwork-gem readme. Chạy schedules:

  clockwork clock.rb
  Starting clock for 4 events: [ frequent.job less.frequent.job hourly.job midnight.job ]
  Triggering frequent.job

Sử dụng queueing

Như đã nói ở trên, chúng ta cần một hệ thống xử lý hàng đợi thay vì thực thi schedule ngay trong file clock.rb. Để làm điều này chúng ta sử dụng một số công cụ hỗ trợ như DelayJob, Beanstalk/Stalker, RabbitMQ/Minion hay Resque.

Ví dụ dùng Beanstalk/Staker:

      require 'stalker'

      handler { |job| Stalker.enqueue(job) }

      every(1.hour, 'feeds.refresh')
      every(1.day, 'reminders.send', :at => '01:30')

Hệ thống queueing không yêu cầu nạp toàn bộ ứng dụng của bạn, vì vậy mà sẽ giảm đi gánh nặng cho bộ nhớ.

Kết luận

Việc thử nghiệm một công cụ lập lịch mới thay cho cron - vốn được sử dụng trong thời gian dài và đã chứng minh được hiệu quả không đơn giản. Tuy nhiên với những hạn chế cố hữu của nó, thay thế cron bởi clockwork là sự lựa chọn sáng suốt.