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)**,这也是为何我们刚刚等了很长时间
function | Async | Queues | Delayed | Priorities | Timeout | Retries |
---|---|---|---|---|---|---|
Backburner | Yes | Yes | Yes | Yes | Job | Global |
Delayed Job | Yes | Yes | Yes | Job | Global | Global |
Qu | Yes | Yes | No | No | No | Global |
Que | Yes | Yes | Yes | Job | No | Job |
queue_classic | Yes | Yes | No* | No | No | No |
Resque | Yes | Yes | Yes (Gem) | Queue | Global | Yes |
Sidekiq | Yes | Yes | Yes | Queue | No | Job |
Sneakers | Yes | Yes | No | Queue | Queue | No |
Sucker Punch | Yes | Yes | No | No | No | No |
Active Job Inline(默认的) | No | Yes | N/A | N/A | N/A | N/A |
Active Job | Yes | Yes | Yes | No | No | No |
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
相关文章推荐
- Memcached FAQ(2) 集群架构方面的问题
- My SQL 函数-----日期函数 day() 、month()、year()
- (OK) [android-x86-6.0-rc1] /system/xbin/quagga/sbin/seem_init.sh
- node.js中的express框架安装
- shell中的大括号和小括号
- Linux day1--如何在VMware上新建Linux系统的虚拟机
- shell中的大括号和小括号
- shell中的大括号和小括号
- shell中的大括号和小括号
- shell中的大括号和小括号
- shell中的大括号和小括号
- 用eclipse加载别人的工程,报错Target runtime com.genuitec.runtime.generic.jee60 is not defined
- PAT乙级1001. 害死人不偿命的(3n+1)猜想 (15)
- 常用子网掩码
- Ruby On Rails-2.0.2源代码分析(1)-Rails的启动
- MongoDB操作
- java序列号 SerializeUID
- hdu 5158 Have meal(模拟)
- 获取WINDOWS下当前用户路径 USERPROFILE
- 在 Linux 上安装使用 VirtualBox 的命令行管理界面 VBoxManage