您的位置:首页 > 其它

ActiveJob + sidekiq做异步执行任务

2016-07-16 10:04 316 查看

初探ActiveJob

简介

ActiveJob 是 Rails 4.2 新加入的功能。这个东西在beta阶段rubyChina就已经有很多高手关注了,无奈自己的项目使用的是4.1.5,升级到4.2 的时候其他gem又有很多依赖有问题,所以没在第一时间使用。今天补个课。ActiveJob 是Rails自己开发运行后台程序的模块,常用于执行运行时间可能很长的工作(比如发送注册邮件)。当然这种需求实际上非常普遍,所以rails 也有相应的第三方gem来解决这个需求,比如著名的Sidekiq和Resque等。**ActiveJob的出现不是为了代替他们**,而是统一了原来Resque、Sidekiq 等其他gem对后台运行程序的各种千奇百怪的写法。

定义

ActiveJob 的使用官方文档已经给出了示例首先在命令行中使用 
rails
g job JOBNAME
 来新建一个任务比如这里
➜  my_rails42 git:(master) ✗ rails g job add_lots_of_users
invoke  test_unit
create    test/jobs/add_lots_of_users_job_test.rb
create  app/jobs/add_lots_of_users_job.rb
➜  my_rails42 git:(master) ✗
我们打开add_lots_of_users_job.rb,可以看到下列内容
class AddLotsOfUsersJob < ActiveJob::Base
queue_as :default

def perform(*args)
# Do something later
end
end
我们可以将耗时的内容写入
perform
def perform(*args)
# Do something later
sleep 10
1000.times do |index|
user = User.new
user.name = "atpking#{index}"
user.save
end
end
我们可以看到,我在job 里建立了一个作业,先睡10秒,再插入1000条数据到数据库中至此,我们就成功建立了一个job了,接下来,就是使用了

使用

官方demo讲的非常简单,就是在你使用的地方用这个句子:
XXJob.perform_later
PARAMS
比如我这里
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]

# GET /users
# GET /users.json
def index
AddLotsOfUsersJob.perform_later
@users = User.all
end
end
我们运行一下试试运行过程中发现**不像我们预想的那样**,而是访问index 的时候,活生生的等待了10多秒,在获得@users
[ActiveJob] [AddLotsOfUsersJob] [e191c62d-68a9-425f-8a94-b9fe080c141c]    (0.8ms)  commit transaction
[ActiveJob] [AddLotsOfUsersJob] [e191c62d-68a9-425f-8a94-b9fe080c141c]    (0.0ms)  begin transaction
[ActiveJob] [AddLotsOfUsersJob] [e191c62d-68a9-425f-8a94-b9fe080c141c]   SQL (0.2ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "atpking999"], ["created_at", "2015-04-20 04:30:29.320703"], ["updated_at", "2015-04-20 04:30:29.320703"]]
[ActiveJob] [AddLotsOfUsersJob] [e191c62d-68a9-425f-8a94-b9fe080c141c]    (0.6ms)  commit transaction
[ActiveJob] [AddLotsOfUsersJob] [e191c62d-68a9-425f-8a94-b9fe080c141c] Performed AddLotsOfUsersJob from Inline(default) in 12789.38ms
User Load (2.1ms)  SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (186.7ms)
Completed 200 OK in 13210ms (Views: 392.6ms | ActiveRecord: 1166.0ms)
注意看上面,很多歌ActiveJob 完毕了之后,输出
Performed
AddLotsOfUsersJob from Inline(default) in 12789.38ms
,再执行的
select
* from users
也就是说,默认情况下的ActiveJob 跟我们使用的方法没什么区别,
是阻塞
的,实际上官方文档也说明了4 Job ExecutionIf no adapter is set, the job is immediately executedIf no adapter is set, the job is immediately executed.那么我们需要给ActiveJob 指定一个Adapter 了。官方有支持以下的adapter,功能有所不同,需要注意。如果没设定,则是默认的 Active Job Inline ,可以看到一个悲剧,**不支持异步(Async)**,这也是为何我们刚刚等了很长时间
functionAsyncQueuesDelayedPrioritiesTimeoutRetries
BackburnerYesYesYesYesJobGlobal
Delayed JobYesYesYesJobGlobalGlobal
QuYesYesNoNoNoGlobal
QueYesYesYesJobNoJob
queue_classicYesYesNo*NoNoNo
ResqueYesYesYes (Gem)QueueGlobalYes
SidekiqYesYesYesQueueNoJob
SneakersYesYesNoQueueQueueNo
Sucker PunchYesYesNoNoNoNo
Active Job Inline(默认的)NoYesN/AN/AN/AN/A
Active JobYesYesYesNoNoNo
我选用了sidekiq 作为Adapter,注意这里,你必须要安装过sidekiq, 没安装自然需要你Gemfile 里加一句咯 同时还要安装redis,之后在命令行使用 redis-server & 启用redis 同时也得在命令行里启用sidekiq,直接输入sidekiq & 即可之后我们需要指定sidekiq 为我们的adapter,我们需要在application.rb 里加入一句话
config.active_job.queue_adapter
= :sidekiq
再次运行index 页面,我们看rails 的日志,就变成了先执行Select * from Users,返回页面结果,再继续执行jobs的内容了。
Started GET "/users" for ::1 at 2015-04-20 12:16:20 +0800
Processing by UsersController#index as HTML
[ActiveJob] Enqueued AddLotsOfUsersJob (Job ID: 50372234-6cf7-4ad2-b886-fd3029f4ea3d) to Sidekiq(default)
2015-04-20T04:16:20Z 79432 TID-ouzlum9ig ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper JID-eb96be6e314f6926583a1267 INFO: start
User Load (0.3ms)  SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (4.1ms)
Completed 200 OK in 72ms (Views: 57.8ms | ActiveRecord: 0.5ms)

Started GET "/assets/jquery_ujs.self-8e98a7a072a6cee1372d19fff9ff3e6aa1e39a37d89d6f06861637d061113ee7.js?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/users.self-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/jquery.self-d03a5518f45df77341bdbe6201ba3bfa547ebba8ed64f0ea56bfa5f96ea7c074.js?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/application.self-e80e8f2318043e8af94dddc2adad5a4f09739a8ebb323b3ab31cd71d45fd9113.css?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/scaffolds.self-a98ac27100e3e5ca7065dbd7c898e5afa02690ec2ef84ccc02f65c4c20057b83.css?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/turbolinks.self-c37727e9bd6b2735da5c311aa83fead54ed0be6cc8bd9a65309e9c5abe2cbfff.js?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/users.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" for ::1 at 2015-04-20 12:16:21 +0800

Started GET "/assets/application.self-3a3c8b61bda630ee689740ce7cbd0dd8ea6fdd45e2c42eef4661ab38cf268afe.js?body=1" for ::1 at 2015-04-20 12:16:21 +0800
2015-04-20T04:16:33Z 79432 TID-ouzlum9ig ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper JID-eb96be6e314f6926583a1267 INFO: done: 12.828 sec
请注意上面的这两句话
2015-04-20T04:16:20Z 79432 TID-ouzlum9ig ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper JID-eb96be6e314f6926583a1267 INFO: start

2015-04-20T04:16:33Z 79432 TID-ouzlum9ig ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper JID-eb96be6e314f6926583a1267 INFO: done: 12.828 sec
怎么取消应该看你用的是哪个 gem ,比如 sidekiq 的https://github.com/mperham/sidekiq/wiki/API#scheduled。另外 ActiveJob 只是统一接口,很多后台任务的 gem 的其他高级功能,是没有在 ActiveJob 里边提供的,比如 Sidekiq 提到的: https://github.com/mperham/sidekiq/wiki/Active-Job#active-job-introductionNote that more advanced Sidekiq features cannot be controlled or configured via ActiveJob, e.g. saving backtraces.简单看了下 ActiveJob 里边的代码,发现 ActiveJobAdapter 里边都是主要只提供 
.enqueue
 这个接口,用于 ActiveJob 将任务塞进对应的队列,所以基本上断定 ActiveJob 并没有封装清理队列的相关逻辑,需要的直接用对应的 gem 提供的接口操作,比如这里提到的如何移除的方式:https://github.com/mperham/sidekiq/wiki/API#scheduled
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: