"dekayed_job"是一个ruby gem,在Rails环境中用来执行任务的后台进程,用来增加页面渲染的速度。Delayed::Job允许将任务转至后台异步处理。
试想以下场景:
如果不用delayed_job, 则会出现:
有了delayed_job, 则可以让delayed_job在后台处理。
git clone https://github.com/testcara/ROR_Blog.git
gem 'delayed_job_active_record'
bundle install --without production
$ rails g delayed_job:active_record
Running via Spring preloader in process 7751
create bin/delayed_job
chmod bin/delayed_job
create db/migrate/20181225082621_create_delayed_jobs.rb
生成的这两个文件:
1. delayed_job: 执行在queue中的jobs
2. db/migrate/*.rb: 用来创建db去存储job信息(priority, attempts, handler, last_error, run_at, queue等
$ rake db:migrate
== 20181225082621 CreateDelayedJobs: migrating ================================
-- create_table(:delayed_jobs, {:force=>true})
-> 0.0030s
-- add_index(:delayed_jobs, [:priority, :run_at], {:name=>"delayed_jobs_priority"})
-> 0.0005s
== 20181225082621 CreateDelayedJobs: migrated (0.0038s) =======================
[Click and drag to move]
更新application.rb
config.active_job.queue_adapter = :delayed_job
运行delayed_job
bin/delayed_job start
# If there is no error, you would get one pid. Otherwise, check the error.
# Usually, we need 'daemon' gem file to run the job. we use the way in the production mode
# The another way to trigger delayed_jobs is to run:
# rake jobs:work
# we use it in the development mode
将tasks改为delayed tasks
$ # Previously, users can update posts instantly.
$ # If we make the 'post.update' action as one delayed action 'post.delay.update', then we can update the post successfully but in fact the real update action is not triggered instantly but is inserted to delayed_job queues.
$ git diff app/controllers/posts_controller.rb
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 7f02217..ed31a7f 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -32,7 +32,7 @@ class PostsController < ApplicationController
end
def update
- if @post.update(post_params)
+ if @post.delay.update(post_params)
redirect_to @post, notice: "Update successfully!"
else
render 'edit'
从log里面我们可以看到不断有delayed job在执行queues中操作。本文的案例不是一个很好的案例,因为更新log实时操作更合适。
配置delayed_jobs
$ # Here just one config delayed_jobs, for more advanced usage, you can read following content
$ cat config/initializers/delayed_job_config.rb
# whether the job will be clean if it is failed
Delayed::Worker.destroy_failed_jobs = false
# If there is no jobs lefe, sleep 60s then to check the queue
Delayed::Worker.sleep_delay = 60
# If the job is failed at the first time, try more 2 times
Delayed::Worker.max_attempts = 3
# If the unfinished job has been kept for 5 minutes, let us mark it as 'failed'
Delayed::Worker.max_run_time = 5.minutes
# If there are available jobs, read the first 10 ones from the queue
Delayed::Worker.read_ahead = 10
# By default all jobs will be queued without a named queue. A default named queue can be specified by using the following parameter
Delayed::Worker.default_queue_name = ‘default’
# Testing env does not support delayed_job
Delayed::Worker.delay_jobs = !Rails.env.test?
# Make the worker to raise a SignalException causing the running job to abort and be unlocked, which makes the job available to other workers.
Delayed::Worker.raise_signal_exceptions = :term
# Delayed jobs log path
Delayed::Worker.logger = Logger.new(File.join(Rails.root, ‘log’, ‘delayed_job.log’))