Bài viết chủ yếu giúp cho các bạn hiểu một cách đơn giản active job là gì?. Cách tạo, thực thi các công việc(jobs) chạy nền trong Ruby On Rails(RoR). Sau bài viết này bạn sẽ có thể:

1. Làm thế nào để tạo jobs.

2. Làm thế nào để sắp xếp các jobs.

3. Làm thế nào để chạy jobs ở backgound (chạy nền, chạy ngầm).

4. Làm thế nào gửi mail từ ứng dụng sử dụng active job.

I. Giới thiệu

Active Jobs là một framework cho việc thiết lập các jobs và làm chúng có thể chạy trên nhiều backends. Hiểu đơn giản hơn là nó sẽ tạo ra 1 luồng riêng giống trong Java để thực hiện một công việc khác mà không ảnh hưởng đến luồng chính. Điều đó làm tăng trải nghiệm người dùng. Những jobs chủ yếu ở đây là việc đặt lịch dọn dẹp rác, hay việc tính toán phí hoặc gửi mail. Mọi thứ có thể được chia thành các phần nhỏ hơn của công việc để chạy song song. Điều đó có thể giúp tăng tốc độ hệ thống lên rất nhiều thay vì chạy theo cách truyền thống.

II. Mục đích của Active Jobs

Mục đích chính là để đảm bảo rằng tất cả các ứng ụng Rails sẽ có một cơ sở hạ tầng thích hợp. Chúng ta có thể sau đó có các đặc điểm framework và các gem khác được xây trên nền tảng đó mà không phải lo lắng về sự khác nhau API giữa các job chạy ví dụ như Delayed Job và Resque.

III. Việc tạo một job

Trong phần này sẽ cung cấp một hướng dẫn chi tiết để tạo một job và sắp xếp nó trong hàng đợi.

1. Tạo job

Active Job cung cấp một Rails generator để tạo các jobs. Đoạn code dưới đây sẽ tạo một job trong thư mục app/jobs:

bin/rails generate job guests_cleanup
invoke  test_unit
create    test/jobs/guests_cleanup_job_test.rb
create  app/jobs/guests_cleanup_job.rb

Bạn cũng có thể tạo một job mà sẽ chạy trên một hàng cụ thể qua câu lệnh:

bin/rails generate job guests_cleanup --queue urgent

Nếu bạ không muốn sử dụng một generator, bạn có thể tạo tự tạo file của mình trong thư mục app/jobs, và đảm bảo rằng class bạn tạo kế thừa từ ApplicationJob

Đây là đoạn code một job trông thế nào:

class GuestsCleanupJob < ApplicationJob
  queue_as :default

  def perform(*guests)
    # Do something later
  end
end

Lưu ý rằng bạn có thể định nghĩa perform với bao nhiêu arguments mà bạn muốn.

2. Đặt thứ tự Job

Đặt thứ tự một job giống như:

# Đặt thứ tự một job được thi hành ngay khi hệ thống hàng đợi trống.

GuestsCleanupJob.perform_later guest
# Đặt thứ tự một job được thi hành vào buổi chiều hôm sau.

GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
# Đặt thứ tự một job đucojw thi hành sau 1 tuần kể từ bây giờ.

GuestsCleanupJob.set(wait: 1.week).perform_later(guest)
# `perform_now` và `perform_later` sẽ gọi `perform` nên bạn có thể truyền các arguments mà được định nghĩa sau đó.

GuestsCleanupJob.perform_later(guest1, guest2, filter: 'some_filter')

Tất cả đơn giản chỉ có vậy thôi.

IV. Thực thi Job

Cho việc đặt tứ tự và thực thi các job trong production bạn cần cài đặt một backend queuing. Rails chỉ cung cấp một tiến trình hệ thống hàng đợi mà chỉ giữ các jobs trong RAM. nếu mà tiến trình mà bị lỗi hoặc hệ thống sẽ bị reset thì tất cả các jobs sẽ bị mất với sự mặc định không đồng bộ với back-end. Điều này có lẽ là ổn đối với những app nhỏ hoặc với các jobs không quan trọng nhưng phần lớn các app production sẽ cần một backend ổn định.

1. Backends

Active Job có các adapter tích hợp cho đa dạng các queuing backend như(Sidekiq, Resque, Delayed Job, …). Để có một danh sách cập nhật của các adapters bạn có thể xem tài liệu API bên dưới ActiveJob::QueueAdapters.

2. Cài đặt Backend

Bạn có thể dễ dàng cài đặt queing backend như sau:

# config/application.rb
module YourApp
  class Application < Rails::Application
    # Be sure to have the adapter's gem in your Gemfile
    # and follow the adapter's specific installation
    # and deployment instructions.
    config.active_job.queue_adapter = :sidekiq
  end
end

Bạn cũng có thể cấu hình backend của bạn trên một nền tảng job.

class GuestsCleanupJob < ApplicationJob
  self.queue_adapter = :resque
  #....
end

# Now your job will use `resque` as it's backend queue adapter overriding what
# was configured in `config.active_job.queue_adapter`.

3. Start Backend

Khi các jobs chạy song song với ứng dụng Rails, phần lớn các thư việc cần bạn start một queing service cụ thể cho tiến trình job để họat động. Tham khảo các tài liệu thư viện chó sự hướng dẫn để start queue backend.

Dưới đây là một danh sách các tài liệu

V. Queues

Phầnlonws các adapter hỗ trợ cho đa dạng các queues. Với Active Job bạn có thể đặt lịch job để chạy trên một queue cụ thể.

class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

Bạn có thể thêm vào đầu tên queue cho tất các jobs của bạn mà sử dụng config.active_job.quêu_name_prefix in application.rb:

# config/application.rb
module YourApp
  class Application < Rails::Application
    config.active_job.queue_name_prefix = Rails.env
  end
end

# app/jobs/guests_cleanup_job.rb
class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

# Now your job will run on queue production_low_priority on your
# production environment and on staging_low_priority
# on your staging environment

Tiền tố tên mặc định dầu trước là ‘_’. Điều này có thể được thay đổi bằng việc cài đặt config.active_job.queue_name_delimiter trong application.rb

# config/application.rb
module YourApp
  class Application < Rails::Application
    config.active_job.queue_name_prefix = Rails.env
    config.active_job.queue_name_delimiter = '.'
  end
end

# app/jobs/guests_cleanup_job.rb
class GuestsCleanupJob < ApplicationJob
  queue_as :low_priority
  #....
end

# Now your job will run on queue production.low_priority on your
# production environment and on staging.low_priority
# on your staging environment

Nếu bạn muốn điều khiển queue nào một job được chạy thì ban có thể truyền một :queue với lựa chọn #set:

MyJob.set(queue: :another_queue).perform_later(record)

Để control queue từ vị trí job bạn có thẻ truyền một block #queue_as. Block sẽ được thực thi:

class ProcessVideoJob < ApplicationJob
  queue_as do
    video = self.arguments.first
    if video.owner.premium?
      :premium_videojobs
    else
      :videojobs
    end
  end

  def perform(video)
    # Do process video
  end
end

ProcessVideoJob.perform_later(Video.last)

VI. Kết luận

Bài này chủ yếu nhằm mục đích giới thiệu và hướng dẫn cách sử dụng cơ bản nhất về Active Job trong các ứng dụng Ruby On Rails để giúp tăng tốc độ thực thi của ứng dụng và nâng cao trải nghiệm người dùng.