Background Job with Active Job
Bài đăng này đã không được cập nhật trong 5 năm
1. Background job:
- Đôi khi chúng ta cần implement 1 feature nào đó thực hiện nhiều action khác nhau bao gồm cả các action
- Ví dụ như khi user đăng ký account mới thì sẽ gửi confirm email cho user, khi KOL của shop đăng bài thì sẽ gửi notification cho toàn bộ follower của KOL, ...
- Nếu thực hiện tuần tự đầy đủ các action xong mới trả response về cho user thì sẽ chờ khá lâu, ảnh hưởng đến trải nghiệm của user, ví dụ như khi số followr của KOL tăng lên thì mỗi lần đăng bài thì sẽ gửi notification đến nhiều user hơn và KOL cũng phải chờ lâu hơn.
- Trong các trường hợp đó, ta sẽ đưa các action nào vào queue, hệ thống sẽ enqueue và thực hiện chạy ngầm các action này, khi đó các action này được gọi là background job.
2. Active Job:
a. Introduction:
Active Job
là framework của Rails cho phép ta khai báo các background job khác nhau- Ta có thể sử dụng
Active Job
với các queue backend khác nhau như Delayed Job, Sidekiq hoặc Resque. - Danh sách các queue backend đầy đủ của Active Job được update tạo đây.
Active Job
đảm bảo chúng ta có thể thay đổi qua lại giữa các queue backend mà không cần phải viết lại các job đã implement trước đó.
b. Creating a job:
i. Create demo app:
- Chạy command tạo rails app
rails new demo_active_job_revise
- Chạy command tạo model user
rails g model user name:string email:string rails db:migrate
- Thêm gem
ffaker
vào Gemfile# Gemfile gem "ffaker"
- Chạy command để install gem
bundle install
- Tạo seed users
# db/seeds.rb 10.times do User.create name: FFaker::Name.name , email: FFaker::Internet.email end
- Chạy command để tạo seed users
rails db:seed
ii. Create the Job:
- Chúng ta sẽ tạo 1 background job để tạo random user tương tự như cách ta đã làm khi tạo seed users.
- Chạy command để tạo job.
rails g job create_random_user
- Generator sẽ tạo file
app/jobs/create_random_user_job.rb
như sau# app/jobs/create_random_user_job.rb class CreateRandomUserJob < ApplicationJob queue_as :default def perform(*args) # Do something later end end
- Ta có thể truyền thêm ham số
--queue
khi tạo jobrails g job create_random_user --queue urgent
- Khi đó generator sẽ tạo file
app/jobs/create_random_user_job.rb
như sau# app/jobs/create_random_user_job.rb class CreateRandomUserJob < ApplicationJob queue_as :urgent def perform(*args) # Do something later end end
- Update lại hàm
perform
# app/jobs/create_random_user_job.rb def perform() User.create name: FFaker::Name.name , email: FFaker::Internet.email end
iii. Enqueue the Job:
- Để enqueue job ta có thể gọi
# Enqueue a job to be performed as soon the queuing system is free CreateRandomUserJob.perform_later
- Khi đó ta sẽ thu đươc log trên console
Enqueued CreateRandomUserJob (Job ID: 6fa80570-7b2c-4263-b97a-e707797cadd6) to Async(default) => #<CreateRandomUserJob:0x00000000046de8c8 @arguments=[], @job_id="6fa80570-7b2c-4263-b97a-e707797cadd6", @queue_name="default", @priority=nil, @executions=0, @provider_job_id="c881286e-b834-46c5-b75a-8b97ab0d51d8"> 2.5.1 :002 > Performing CreateRandomUserJob (Job ID: 6fa80570-7b2c-4263-b97a-e707797cadd6) from Async(default) (0.1ms) begin transaction User Create (0.2ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Earl Moore"], ["email", "frances@durganoconnell.name"], ["created_at", "2019-07-01 04:19:25.463957"], ["updated_at", "2019-07-01 04:19:25.463957"]] (12.5ms) commit transaction Performed CreateRandomUserJob (Job ID: 6fa80570-7b2c-4263-b97a-e707797cadd6) from Async(default) in 64.11ms
- Hoặc log trên development.log
[ActiveJob] [CreateRandomUserJob] [51ecf695-70c1-4567-b843-3e3cb9319e10] Performing CreateRandomUserJob (Job ID: 51ecf695-70c1-4567-b843-3e3cb9319e10) from Async(default) [ActiveJob] [CreateRandomUserJob] [51ecf695-70c1-4567-b843-3e3cb9319e10] [1m[35m (0.1ms)[0m [1m[36mbegin transaction[0m [ActiveJob] [CreateRandomUserJob] [51ecf695-70c1-4567-b843-3e3cb9319e10] [1m[36mUser Create (0.6ms)[0m [1m[32mINSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)[0m [["name", "Earl Moore"], ["email", "frances@durganoconnell.name"], ["created_at", "2019-07-01 04:19:08.410595"], ["updated_at", "2019-07-01 04:19:08.410595"]] [ActiveJob] [CreateRandomUserJob] [51ecf695-70c1-4567-b843-3e3cb9319e10] [1m[35m (15.6ms)[0m [1m[36mcommit transaction[0m [ActiveJob] [CreateRandomUserJob] [51ecf695-70c1-4567-b843-3e3cb9319e10] Performed CreateRandomUserJob (Job ID: 51ecf695-70c1-4567-b843-3e3cb9319e10) from Async(default) in 20.48ms [ActiveJob] Enqueued CreateRandomUserJob (Job ID: 239274e1-161d-455f-a795-9c0083377e96) to Async(default)
- Ta có thể sử dụng hàm
set
và truyền thêm params để tùy chỉnh thời gian job đươc enqueue# Enqueue a job to be performed tomorrow at noon. CreateRandomUserJob.set(wait_until: Date.tomorrow.noon).perform_later # Enqueue a job to be performed 1 week from now. CreateRandomUserJob.set(wait: 1.week).perform_later
c. Exception:
Active Job
sử dụngrescue_from exception
để catch và handle exceptionclass UpdateRandomUserJob < ApplicationJob queue_as :default rescue_from(ActiveRecord::RecordNotFound) do |exception| puts "Please check again ActiveRecord::RecordNotFound #{exception.message}" end def perform(user_id) user = User.find user_id user.update_attributes name: FFaker::Name.name , email: FFaker::Internet.email end end
d. Document:
All rights reserved