`
sg552
  • 浏览: 620616 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
47437293-94b9-3b04-9152-8971c7580049
白手起家学习使用Flex
浏览量:18716
社区版块
存档分类
最新评论

delayed_job 的 基本用法

阅读更多
delayed_job 是用来做某些可以延后的,对时间要求不高的任务,例如: 发送1W个邮件,处理10W个数据,不能在规定的时间内(例如1秒)立即执行完的任务。

delayed_job 有两个版本,一个是最初的:
https://github.com/tobi/delayed_job
另一个是改进的:
https://github.com/collectiveidea/delayed_job

我用的是第二个。它们用法几乎一样,除了在 优先级方面(priority ),后者是数字越大,优先级越低。

文档方面很奇怪,建议两者都要看,互相综合,才能看完整。

下面把我的一点心得贴出来:

1. worker 至关重要。默认是启动一个,看起来是单线程。 启动时配置参数:
$ script/delayed_job -n 4 start  (启动4个worker)

2. 每个job一旦被执行,那么它被lock住,(lock=true),等到该JOB彻底被执行完毕,才会把它从delayed_job 表中删除掉。

3. 可以在 config/initializers 中进行配置:

# delayed_job_config.rb
Delayed::Worker.destroy_failed_jobs = true
Delayed::Worker.sleep_delay = 30
Delayed::Worker.max_attempts = 5 
Delayed::Worker.max_run_time = 10.minutes


4. 几个hooks:
从源代码中可以看到几个hooks:
      def invoke_job
        hook :before
        payload_object.perform
        hook :success
      rescue Exception => e
        hook :error, e
        raise e
      ensure
        hook :after
      end 


比如,定义个before:
class ParanoidNewsletterJob < NewsletterJob
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def before(job)
    record_stat 'newsletter_job/start'
  end
end


5. priority 很重要。 可以为某些任务设置。 但是不要被他所迷惑。 在多worker情况下是不准确的。


例如,我有2 种job, 一种是 drink_water, 一种是: eat_food
那么,光设置 priority 还不行,在多个worker下,还要设置 一个wait_job.

class EatFoodJob < Struct.new(:job_name)
  def perform
    Rails.logger.info "===(#{job_name}) running"
    sleep_time = 1 + rand(5)
    sleep sleep_time
    Rails.logger.info "===(#{job_name}) after #{sleep_time} sleep, done "
  end 
end


class WaitJob < Struct.new(:job_name)
  def perform
    Rails.logger.info "===(#{job_name}, #{self.class}) running"
    loop do
      break unless DelayedJob.where(:priority => 10).all.size > 0 
      Rails.logger.info " === !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds"
      sleep 1
    end 
    Rails.logger.info "===(#{job_name}) done "
  end 
end


class DrinkWaterJob < Struct.new(:job_name)
  def perform
    Rails.logger.info "===(#{job_name}, #{self.class}) running"
    sleep_time = 5 + rand(5)
    sleep sleep_time
    Rails.logger.info "===(#{job_name}) after #{sleep_time} sleep, done "
  end 
end


然后,启动4个worker:
$ script/delayed_job -n 4 start

最后,我们要设置4个wait_job (对应4个worker) :
(1..10).each do |i|
  Delayed::Job.enqueue DrinkWaterJob.new("drink#{i}"), :priority => 10
  Delayed::Job.enqueue EatFoodJob.new("eat#{i}"), :priority => 20
end
(1..4).each do |i|
  Delayed::Job.enqueue WaitJob.new("wait#{i}"), :priority => 15
end


最后,可以从日志中看出,所有的 eat_food( priority = 20  ) 都在 drink_water( priority = 10) 的任务之后执行了,没有越轨的行为。

引用
===(drink1, DrinkWaterJob) running
===(drink2, DrinkWaterJob) running
===(drink3, DrinkWaterJob) running
===(drink4, DrinkWaterJob) running
===(drink3) after 7 sleep, done
===(drink5, DrinkWaterJob) running
===(drink2) after 8 sleep, done
===(drink6, DrinkWaterJob) running
===(drink1) after 9 sleep, done
===(drink7, DrinkWaterJob) running
===(drink4) after 9 sleep, done
===(drink8, DrinkWaterJob) running
===(drink6) after 7 sleep, done
===(drink5) after 8 sleep, done
===(drink9, DrinkWaterJob) running
===(drink10, DrinkWaterJob) running
===(drink7) after 7 sleep, done
===(wait1, WaitJob) running
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
===(drink8) after 8 sleep, done
===(wait2, WaitJob) running
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
===(drink9) after 6 sleep, done
===(wait3, WaitJob) running
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
=== !!!!!!  jobs: priority => 10 not done, now wait for 5 seconds
===(drink10) after 9 sleep, done
===(wait4, WaitJob) running
===(wait4) done
===(eat1) running
===(wait2) done
===(eat2) running
===(wait1) done
===(eat3) running
===(wait3) done
===(eat4) running
===(eat1) after 1 sleep, done
===(eat5) running
===(eat4) after 3 sleep, done
===(eat6) running
===(eat3) after 4 sleep, done
===(eat7) running
===(eat5) after 4 sleep, done
===(eat8) running
===(eat2) after 5 sleep, done
===(eat9) running
===(eat7) after 3 sleep, done
===(eat10) running
===(eat8) after 3 sleep, done
===(eat6) after 5 sleep, done
===(eat9) after 5 sleep, done
===(eat10) after 3 sleep, done



如果不加入那4个wait_job, 就会看到, 在多个worker之下, 有些JOB 不是严格的按照priority来执行的。 这个非常姚明。。。见下面的日志:

(1..10).each do |i|
  Delayed::Job.enqueue DrinkWaterJob.new("drink#{i}"), :priority => 10
  Delayed::Job.enqueue EatFoodJob.new("eat#{i}"), :priority => 20
end


引用

===(drink1, DrinkWaterJob) running
===(drink2, DrinkWaterJob) running
===(drink3, DrinkWaterJob) running
===(drink4, DrinkWaterJob) running
===(drink1) after 8 sleep, done
===(drink5, DrinkWaterJob) running
===(drink2) after 8 sleep, done
===(drink6, DrinkWaterJob) running
===(drink3) after 8 sleep, done
===(drink7, DrinkWaterJob) running
===(drink4) after 7 sleep, done
===(drink8, DrinkWaterJob) running
===(drink5) after 6 sleep, done
===(drink9, DrinkWaterJob) running
===(drink8) after 5 sleep, done
===(drink10, DrinkWaterJob) running
===(drink7) after 8 sleep, done
===(eat1) running
===(drink6) after 9 sleep, done
===(eat2) running
===(drink9) after 5 sleep, done
===(eat3) running
===(eat1) after 2 sleep, done
===(eat4) running
===(eat4) after 2 sleep, done
===(eat5) running
===(eat3) after 4 sleep, done
===(eat6) running
===(eat2) after 5 sleep, done
===(eat7) running
===(drink10) after 9 sleep, done
===(eat8) running
===(eat7) after 2 sleep, done
===(eat9) running
===(eat6) after 3 sleep, done
===(eat8) after 1 sleep, done
===(eat10) running
===(eat5) after 4 sleep, done
===(eat9) after 1 sleep, done
===(eat10) after 2 sleep, done

分享到:
评论
2 楼 sg552 2013-01-25  
你说的是对的。

所以我只好单独写了一个job 来保证 低优先级的JOB 在所有 高优先级JOB ‘完成’ 之后,才被开始执行

matx2202 写道
偶然间看到这个文章,整理的非常好,谢谢博主。

但是关于顺序执行那段我想可能是你理解错了,priority只是保证开始执行的顺序性,并不保证所有drink都必须在eat之前完成

1 楼 matx2202 2013-01-24  
偶然间看到这个文章,整理的非常好,谢谢博主。

但是关于顺序执行那段我想可能是你理解错了,priority只是保证开始执行的顺序性,并不保证所有drink都必须在eat之前完成

相关推荐

    delayed_job_celluloid

    celluloid 添加到您的 gem 文件中 gem 'delayed_job_celluloid'运行捆绑安装 bundle install delayed_job_celluloid要将启动脚本添加到您的脚本目录,请运行生成器 rails generate delayed_job_celluloid 用法首先,...

    delay_job_progress:扩展为延迟::工作

    建立添加到Gemfile:gem'delayed_job_progress gem 'delayed_job_progress' bundle install rails g delayed_job:progress rake db:migrate配置和用法考虑一下: class User &lt; ActiveRecord xss=removed&gt; :record , ...

    delayed_webhook:使用 HTTParty 和 delay_job 执行健壮的 webhook

    基本用法 使用DelayedWebhook.enqueue! 为您的应用程序运行 webhook: method = :get # HTTP method to use (must be supported by HTTParty) path = ... # Webhook target, passed as the first argument to the ...

    delay_job:数据库支持的异步优先级队列-从Shopify中提取

    该库围绕一个delay_jobs表展开,该表可以使用以下方法创建: script/generate delayed_job 创建的表如下所示: create_table :delayed_jobs, :force =&gt; true do |table| table.integer :priority, :default =&gt; 0 ...

    delay_paperclip:使用delay_job或Resque在后台处理您的回形针附件

    延迟::回形针 DelayedPaperclip使您可以通过在后台任务中处理附件 为什么? Paperclip最常见的用例是轻松将图像文件附加到ActiveRecord模型。 大多数情况下,这些图像文件将具有多种样式,并且在创建它们时...用法 在

    dj_mon:延迟作业的前端(不再维护)

    delayed_job_mongoid取决于mongoid 3.0这需要Ruby 1.9的,所以不存在用于支持ruby 1.8.7为。用法如果您使用的是Rails = &lt;3.1,或者config.assets.initialize_on_precompile设置为false,则将其添加到config/...

    resque-delayed:Resque 的延迟作业排队

    Resque::延迟Resque 的作业排队延迟。 将仅在指定延迟后或将来特定...用法Resque::Delayed 非常简单。 调用Resque.enqueue_in或Resque.enqueue_at而不是Resque.enqueue例如: class User after_create :send_call_to

    pe_lookup:与'puppet lookup'命令类似,但带有分类器

    pe_lookup 目录 描述 该模块提供一个Puppet命令puppet pe lookup ,该命令输出在Hiera和/或Classifier中定义的键(类...[root@pe-master ~ ] puppet pe lookup puppet_enterprise::profile::console::delayed_job_wor

    poist:在应用程序中执行后台作业处理的简便方法

    与Resque,Sidekiq,delayed_job,Celery,Quartz Scheduler,Hangfire,Gearman等其他解决方案相比,它易于修改和使用 使用手法 安装Java JRE sudo apt-get install default-jre 安装Maven sudo apt-get ...

    qe:多个后台作业库(如 Resque、Sidekiq 和 DelayedJob)的简单界面

    require "qe/delayed_job" require "qe/beanstalk" 您还需要 require 将要使用的库。 如果您将 Rails 与 Bundler 一起使用,您可以简单地要求正确的文件和依赖项。 source :rubygems gem "rails" , "3.2.8" gem ...

    request-log-analyzer:基于您的日志文件创建报告。 支持Rails,Apache,MySQL,Delayed :: Job和其他格式

    请求日志分析器 这是一个简单的命令行工具,可以分析各种格式的请求日志文件以生成性能报告。...安装和基本用法 将request-log-analyzer作为Ruby gem安装(您可能需要先在sudo以root身份运行此命令

    详解Ruby on Rails中的mailer相关使用

    可以利用`delayed_job`这样的背景任务库来异步发送邮件,以提高用户体验。 综上所述,理解并遵循这些最佳实践能够帮助你在Ruby on Rails中构建高效且健壮的Mailer系统,同时确保邮件的可靠性和用户体验。

    jobqueue:由Tarantool支持的作业队列

    推荐的安装库的方法是通过 : composer require tarantool/jobqueue 用法 ./jobqueue ./jobqueue help run 请检查应用程序源代码以获取此库的更完整用法示例。 经营工人 ./jobqueue run &lt; queue&gt; -f worker.log -l...

    Python使用Beanstalkd做异步任务处理的方法共

    工作者进程通常会使用`watch`方法关注一个或多个tube(任务队列),然后使用`reserve`方法获取下一个待处理的任务。处理完成后,调用`delete`方法删除任务,表示任务已完成。 7. **任务TTR(Time To Run)** 每个...

    rails-4.2.0-gems

    它与各种后台作业队列库如Resque、Sidekiq和Delayed Job兼容,极大地提高了应用的响应速度和用户体验。 关于Ruby 4.2.0,最大的亮点是增加了`Symbol#to_proc`的性能优化。这个功能在迭代和函数式编程中广泛使用,...

    PHP Beanstalkd消息队列的安装与使用方法实例详解

    本文将深入探讨PHP环境下Beanstalkd消息队列的安装与使用方法,实例剖析其基本功能、原理、安装步骤、使用技巧以及操作注意事项。 一、Beanstalkd简介 Beanstalkd是一个高性能、轻量级的分布式内存队列系统。它的...

    unix power tools 3ed.pdf

    - **包管理器**: 如`apt`, `yum`, `brew`等的使用方法。 - **源码编译**: 从源代码构建软件的方法。 - **容器化**: 使用Docker等容器技术部署应用程序。 **7.4 Perl (Chapter 41: Perl)** - **Perl语言**: Perl的...

    Laravel框架队列原理与用法分析

    ### Laravel框架队列原理与用法分析 #### 一、队列基础概念 在软件开发过程中,队列是一种常见的用于异步处理数据的技术。通过队列可以将耗时的操作(如发送邮件、处理图片等)从主流程中分离出来,提高系统的响应...

    动词todo与doing的用法区别.doc

    ### 动词 todo 与 doing 的用法区别 在英语语法中,动词形式的变换是构建句式结构的关键部分之一。动词可以变化为不同的形式来满足句子中时态、语气等方面的需求,其中最常见的是动词不定式(to + 原形动词,如 to ...

    pdf-to-png-converter:Rails应用程序将pdf转换为png图像

    这是Rails应用程序,用作沙箱环境,用于尝试使用延迟回形针(Paperclip + Delayed Job)将PDF文档转换为PNG图像的方法。 使用内置于回形针中的ImageMagick,可以完成从PDF到PNG文件的转换和拆分。 资源:

Global site tag (gtag.js) - Google Analytics