Coder Social home page Coder Social logo

collectiveidea / delayed_job Goto Github PK

View Code? Open in Web Editor NEW

This project forked from tobi/delayed_job

4.8K 75.0 955.0 1.4 MB

Database based asynchronous priority queue system -- Extracted from Shopify

Home Page: http://groups.google.com/group/delayed_job

License: MIT License

Ruby 100.00%

delayed_job's Introduction

If you're viewing this at https://github.com/collectiveidea/delayed_job, you're reading the documentation for the master branch. View documentation for the latest release (4.1.11).

Delayed::Job

Gem Version CI Code Climate Coverage Status

Delayed::Job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.

It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:

  • sending massive newsletters
  • image resizing
  • http downloads
  • updating smart collections
  • updating solr, our search server, after product changes
  • batch imports
  • spam checks

Follow us on Twitter to get updates and notices about new releases.

Installation

delayed_job 3.0.0 only supports Rails 3.0+.

delayed_job supports multiple backends for storing the job queue. See the wiki for other backends.

If you plan to use delayed_job with Active Record, add delayed_job_active_record to your Gemfile.

gem 'delayed_job_active_record'

If you plan to use delayed_job with Mongoid, add delayed_job_mongoid to your Gemfile.

gem 'delayed_job_mongoid'

Run bundle install to install the backend and delayed_job gems.

The Active Record backend requires a jobs table. You can create that table by running the following command:

rails generate delayed_job:active_record
rake db:migrate

For Rails 4.2+, see below

Development

In development mode, if you are using Rails 3.1+, your application code will automatically reload every 100 jobs or when the queue finishes. You no longer need to restart Delayed Job every time you update your code in development.

Active Job

In Rails 4.2+, set the queue_adapter in config/application.rb

config.active_job.queue_adapter = :delayed_job

See the rails guide for more details.

Rails 4.x

If you are using the protected_attributes gem, it must appear before delayed_job in your gemfile. If your jobs are failing with:

 ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR:  null value in column "handler" violates not-null constraint

then this is the fix you're looking for.

Upgrading from 2.x to 3.0.0 on Active Record

Delayed Job 3.0.0 introduces a new column to the delayed_jobs table.

If you're upgrading from Delayed Job 2.x, run the upgrade generator to create a migration to add the column.

rails generate delayed_job:upgrade
rake db:migrate

Queuing Jobs

Call .delay.method(params) on any object and it will be processed in the background.

# without delayed_job
@user.activate!(@device)

# with delayed_job
@user.delay.activate!(@device)

If a method should always be run in the background, you can call #handle_asynchronously after the method declaration:

class Device
  def deliver
    # long running method
  end
  handle_asynchronously :deliver
end

device = Device.new
device.deliver

Parameters

#handle_asynchronously and #delay take these parameters:

  • :priority (number): lower numbers run first; default is 0 but can be reconfigured (see below)
  • :run_at (Time): run the job after this time (probably in the future)
  • :queue (string): named queue to put this job in, an alternative to priorities (see below)

These params can be Proc objects, allowing call-time evaluation of the value.

For example:

class LongTasks
  def send_mailer
    # Some other code
  end
  handle_asynchronously :send_mailer, :priority => 20

  def in_the_future
    # Some other code
  end
  # 5.minutes.from_now will be evaluated when in_the_future is called
  handle_asynchronously :in_the_future, :run_at => Proc.new { 5.minutes.from_now }

  def self.when_to_run
    2.hours.from_now
  end

  class << self
    def call_a_class_method
      # Some other code
    end
    handle_asynchronously :call_a_class_method, :run_at => Proc.new { when_to_run }
  end

  attr_reader :how_important

  def call_an_instance_method
    # Some other code
  end
  handle_asynchronously :call_an_instance_method, :priority => Proc.new {|i| i.how_important }
end

If you ever want to call a handle_asynchronously'd method without Delayed Job, for instance while debugging something at the console, just add _without_delay to the method name. For instance, if your original method was foo, then call foo_without_delay.

Rails Mailers

Delayed Job uses special syntax for Rails Mailers. Do not call the .deliver method when using .delay.

# without delayed_job
Notifier.signup(@user).deliver

# with delayed_job
Notifier.delay.signup(@user)

# delayed_job running at a specific time
Notifier.delay(run_at: 5.minutes.from_now).signup(@user)

# when using parameters, the .with method must be called before the .delay method
Notifier.with(foo: 1, bar: 2).delay.signup(@user)

You may also wish to consider using Active Job with Action Mailer which provides convenient .deliver_later syntax that forwards to Delayed Job under-the-hood.

Named Queues

DJ 3 introduces Resque-style named queues while still retaining DJ-style priority. The goal is to provide a system for grouping tasks to be worked by separate pools of workers, which may be scaled and controlled individually.

Jobs can be assigned to a queue by setting the queue option:

object.delay(:queue => 'tracking').method

Delayed::Job.enqueue job, :queue => 'tracking'

handle_asynchronously :tweet_later, :queue => 'tweets'

You can configure default priorities for named queues:

Delayed::Worker.queue_attributes = {
  high_priority: { priority: -10 },
  low_priority: { priority: 10 }
}

Configured queue priorities can be overriden by passing priority to the delay method

object.delay(:queue => 'high_priority', priority: 0).method

You can start processes to only work certain queues with the queue and queues options defined below. Processes started without specifying a queue will run jobs from any queue. To effectively have a process that runs jobs where a queue is not specified, set a default queue name with Delayed::Worker.default_queue_name and have the processes run that queue.

Running Jobs

script/delayed_job can be used to manage a background process which will start working off jobs.

To do so, add gem "daemons" to your Gemfile and make sure you've run rails generate delayed_job.

You can then do the following:

RAILS_ENV=production script/delayed_job start
RAILS_ENV=production script/delayed_job stop

# Runs two workers in separate processes.
RAILS_ENV=production script/delayed_job -n 2 start
RAILS_ENV=production script/delayed_job stop

# Set the --queue or --queues option to work from a particular queue.
RAILS_ENV=production script/delayed_job --queue=tracking start
RAILS_ENV=production script/delayed_job --queues=mailers,tasks start

# Use the --pool option to specify a worker pool. You can use this option multiple times to start different numbers of workers for different queues.
# The following command will start 1 worker for the tracking queue,
# 2 workers for the mailers and tasks queues, and 2 workers for any jobs:
RAILS_ENV=production script/delayed_job --pool=tracking --pool=mailers,tasks:2 --pool=*:2 start

# Runs all available jobs and then exits
RAILS_ENV=production script/delayed_job start --exit-on-complete
# or to run in the foreground
RAILS_ENV=production script/delayed_job run --exit-on-complete

Rails 4: replace script/delayed_job with bin/delayed_job

Workers can be running on any computer, as long as they have access to the database and their clock is in sync. Keep in mind that each worker will check the database at least every 5 seconds.

You can also invoke rake jobs:work which will start working off jobs. You can cancel the rake task with CTRL-C.

If you want to just run all available jobs and exit you can use rake jobs:workoff

Work off queues by setting the QUEUE or QUEUES environment variable.

QUEUE=tracking rake jobs:work
QUEUES=mailers,tasks rake jobs:work

Restarting delayed_job

The following syntax will restart delayed jobs:

RAILS_ENV=production script/delayed_job restart

To restart multiple delayed_job workers:

RAILS_ENV=production script/delayed_job -n2 restart

Rails 4: replace script/delayed_job with bin/delayed_job

Custom Jobs

Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table. Job objects are serialized to yaml so that they can later be resurrected by the job runner.

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end
end

Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.pluck(:email))

To set a per-job max attempts that overrides the Delayed::Worker.max_attempts you can define a max_attempts method on the job

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def max_attempts
    3
  end
end

To set a per-job max run time that overrides the Delayed::Worker.max_run_time you can define a max_run_time method on the job

NOTE: this can ONLY be used to set a max_run_time that is lower than Delayed::Worker.max_run_time. Otherwise the lock on the job would expire and another worker would start the working on the in progress job.

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def max_run_time
    120 # seconds
  end
end

To set a per-job default for destroying failed jobs that overrides the Delayed::Worker.destroy_failed_jobs you can define a destroy_failed_jobs? method on the job

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def destroy_failed_jobs?
    false
  end
end

To set a default queue name for a custom job that overrides Delayed::Worker.default_queue_name, you can define a queue_name method on the job

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def queue_name
    'newsletter_queue'
  end
end

On error, the job is scheduled again in 5 seconds + N ** 4, where N is the number of attempts. You can define your own reschedule_at method to override this default behavior.

NewsletterJob = Struct.new(:text, :emails) do
  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def reschedule_at(current_time, attempts)
    current_time + 5.seconds
  end
end

Hooks

You can define hooks on your job that will be called at different stages in the process:

NOTE: If you are using ActiveJob these hooks are not available to your jobs. You will need to use ActiveJob's callbacks. You can find details here https://guides.rubyonrails.org/active_job_basics.html#callbacks

class ParanoidNewsletterJob < NewsletterJob
  def enqueue(job)
    record_stat 'newsletter_job/enqueue'
  end

  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

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

  def after(job)
    record_stat 'newsletter_job/after'
  end

  def success(job)
    record_stat 'newsletter_job/success'
  end

  def error(job, exception)
    Airbrake.notify(exception)
  end

  def failure(job)
    page_sysadmin_in_the_middle_of_the_night
  end
end

Gory Details

The library revolves around a delayed_jobs table which looks as follows:

create_table :delayed_jobs, :force => true do |table|
  table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue
  table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.
  table.text     :handler                      # YAML-encoded string of the object that will do work
  table.text     :last_error                   # reason for last failure (See Note below)
  table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.
  table.datetime :locked_at                    # Set when a client is working on this object
  table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)
  table.string   :locked_by                    # Who is working on this object (if locked)
  table.string   :queue                        # The name of the queue this job is in
  table.timestamps
end

On error, the job is scheduled again in 5 seconds + N ** 4, where N is the number of attempts or using the job's defined reschedule_at method.

The default Worker.max_attempts is 25. After this, the job is either deleted (default), or left in the database with "failed_at" set. With the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.

The default Worker.max_run_time is 4.hours. If your job takes longer than that, another computer could pick it up. It's up to you to make sure your job doesn't exceed this time. You should set this to the longest time you think the job could take.

By default, it will delete failed jobs (and it always deletes successful jobs). If you want to keep failed jobs, set Delayed::Worker.destroy_failed_jobs = false. The failed jobs will be marked with non-null failed_at.

By default all jobs are scheduled with priority = 0, which is top priority. You can change this by setting Delayed::Worker.default_priority to something else. Lower numbers have higher priority.

The default behavior is to read 5 jobs from the queue when finding an available job. You can configure this by setting Delayed::Worker.read_ahead.

By default all jobs will be queued without a named queue. A default named queue can be specified by using Delayed::Worker.default_queue_name.

If no jobs are found, the worker sleeps for the amount of time specified by the sleep delay option. Set Delayed::Worker.sleep_delay = 60 for a 60 second sleep time.

It is possible to disable delayed jobs for testing purposes. Set Delayed::Worker.delay_jobs = false to execute all jobs realtime.

Or Delayed::Worker.delay_jobs can be a Proc that decides whether to execute jobs inline on a per-job basis:

Delayed::Worker.delay_jobs = ->(job) {
  job.queue != 'inline'
}

You may need to raise exceptions on SIGTERM signals, Delayed::Worker.raise_signal_exceptions = :term will cause the worker to raise a SignalException causing the running job to abort and be unlocked, which makes the job available to other workers. The default for this option is false.

Here is an example of changing job parameters in Rails:

# config/initializers/delayed_job_config.rb
Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_attempts = 3
Delayed::Worker.max_run_time = 5.minutes
Delayed::Worker.read_ahead = 10
Delayed::Worker.default_queue_name = 'default'
Delayed::Worker.delay_jobs = !Rails.env.test?
Delayed::Worker.raise_signal_exceptions = :term
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))

Cleaning up

You can invoke rake jobs:clear to delete all jobs in the queue.

Having problems?

Good places to get help are:

delayed_job's People

Contributors

albus522 avatar atomaka avatar bernardeli avatar betamatt avatar bethesque avatar bkeepers avatar brennovich avatar bryckbost avatar christophermanning avatar davidakachaos avatar dcuddeback avatar defunkt avatar denisahearn avatar edgibbs avatar edwinv avatar gaffneyc avatar iamnader avatar johnnyshields avatar laserlemon avatar lpetre avatar nickmerwin avatar nightshade427 avatar rbriank avatar rdpoor avatar rfroetscher avatar sferik avatar technoweenie avatar willnet avatar wok avatar zbelzer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delayed_job's Issues

Cron job + script/delayed_job launching DJ multiple times?

All-

Maybe I am wrong here but I thought that script/delayed_job checks to see if DJ is already running and prevents it from launching another process. I have a cron job set to run dj via delayed_job start every 10 minutes in case it's not running but I obviously dont want it to launch a new DJ each time:

*/10 * * * * source ~/.profile && ~/current/script/delayed_job start

Any thoughts?

DEPRECATION WARNING with Rails 2.3.5

Not a huge deal, but lib/delayed_job.rb has the following deprecated (as of Rails 2.3.5) line in it:

autoload :ActiveRecord, 'activerecord'

It should be requiring 'active_record', which was a change going back to at least 2.3.2 and probably sooner (haven't looked back any further).

For us, just commenting out the autoload line completely worked, but not sure if that's a general solution. Alternatively, you could load 'active_record' instead of 'activerecord', which should work for most out there (but old enough versions of Rails will break). You could even find out when the 'activerecord' -> 'active_record' transition occurred (again, it's <= 2.3.2) and test for the RAILS_GEM_VERSION and require one or the other accordingly.

Sorry, don't know the 'right' solution here, so couldn't suggest an appropriate patch to pull.

Here's what we get (I raised a dummy exception from activerecord.rb in order to trigger a stack trace, so ignore the "FOOFOO" and the deprecation warning is obviously coming from activerecord.rb:2):

DEPRECATION WARNING: require "activerecord" is deprecated and will be removed in Rails 3. Use require "active_record" instead.. (called from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/activerecord.rb:2)
rake aborted!
FOOFOOFOO
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/activerecord.rb:4
/opt/local/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.2/lib/delayed/job.rb:10
/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in gem_original_require' /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:inrequire'
/opt/local/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:156:in require' /opt/local/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:521:innew_constants_in'
/opt/local/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:156:in require' /opt/local/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.2/lib/delayed_job.rb:5 /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:ingem_original_require'
/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'

...

Log file doesn't get written to

Has anyone had an issue where the daemon never writes to the log file? Otherwise, the daemon behaves normally.

log/delayed_job.log shows up, has the expected ownership and permissions, but never goes beyond a length of 0. Deleting the file and restarting the daemon yields the same results. No errors appear in either the application or web-server log.

The entire contents of my delayed_job_config.rb is:

Delayed::Job.destroy_failed_jobs = false

Thanks in advance.

Problems with delayed_job and acts_as_ferret

Somehow, it seems that though the Rails environment has been loaded, a delayed_job is not able to connect with ferret Drb server and keeps throwing a closed_stream error. There are 2 questions already posted on stackoverflow regarding this:

http://stackoverflow.com/questions/1715268 and
http://stackoverflow.com/questions/1679043/delayedjob-with-actsasferret-in-production-mode

Please help - it seems there could be a problem when a job is spawned!
Am investigating too.

Asynchronous ActionMailer deliveries

I'm trying to make all of my application emails deliver asynchronously using delayed job. I've added the following:

class ActionMailer::Base
  handle_asynchronously :deliver!
end

But this hasn't worked for me. It queues up the job as expected, but the jobs fails with the following error:

undefined method `deliver_without_send_later!' for #<YAML::Object:0x37093d0>

I should also mention that I'm using my fork of delayed_job, which contains one small modification but not one that I would expect to cause this issue. However, in order to duplicate the issue, you may want to take a look at my fork because normally, handle_asynchronously doesn't play nice with punctuated method names. I've sent a pull request.

Issue with script/delayed_job when installing as a gem vs. plugin

When using delayed_job as a gem:

config.gem 'collectiveidea-delayed_job',  :lib => 'delayed_job', :version => '>= 1.8.0', :source => 'http://gems.github.com'

and install then unpacking the gem:

rake gems:install
rake gems:unpack
#or
rake gems:install:dependencies
rake gems:unpack:dependencies

Then you get the new unpacked gem in your rails project: vendor/gems/collectiveidea-delayed_job-1.8.0

However, the script/delayed_job script that is generated has the following:

#!/usr/bin/env ruby

# Daemons sets pwd to /, so we have to explicitly set RAILS_ROOT
RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))

require File.join(File.dirname(__FILE__), *%w(.. vendor plugins delayed_job lib delayed command))
Delayed::Command.new(ARGV).daemonize

When the require line should read:

require File.join(File.dirname(__FILE__), *%w(.. vendor gems collectiveidea-delayed_job-1.8.0 lib delayed command))

Not sure how to handle this besides editing the file or adding in a little if File.exists? handler to require the plugin file if it is there otherwise look for the gem installation, or vice versa, now that it is a gem it should probably be installed as a gem so that people can install specific versions.

~ Tom

Add timestamps to log file

The current Delayed::Job log file does not contain timestamps. I think it is good practice to include timestamps with log message, so it is possible to trace problems in a log file. Moreover, timestamps are required for some of the functionality of request-log-analyzer, which parses Delayed::Job log files to gather statistics.

Any chance timestamps can be added?

delayed_job daemon not starting after upgrade to rails 2.3.5 & ruby 1.8.7

We recently upgraded out ruby/rails environment from rails 2.0.2 & ruby 1.8.6, to rails 2.3.5 & ruby 1.8.7, but now delayed_job does not seem to start correctly (using ruby script/delayed_job -e production).

There is no log file (delayed_job.log) created in the new ruby/rails environment, to tell us what has gone wrong.

When we run the rake task "RAILS_ENV=production rake jobs:work" it seems to work fine.

Looking at linux "top" command, we can see that the delayed_job starts up, but then disappears after a short period of time, assume a unhandled exception has been thrown, but we cannot tell what.

We believe it might be something to do with the incompatibility of the daemons gem v1.0.10 (http://daemons.rubyforge.org/) with the new version of rails?

Is there anyway to further troubleshoot this problem? any help is much appreciated.

Problem with start

When delayed job fail to start through script/delayed_job for any reason, it fails again because of invalid logger usage:

command.rb:59:in `run': undefined local variable or method `logger' for #<Delayed::Command:0x244e0b0> (NameError)

And it becomes realy difficult to debug real problem. Here's the patch:

--- command_orig.rb 2009-10-02 22:16:13.000000000 +0300
+++ command.rb 2009-10-02 22:23:23.000000000 +0300
@@ -56,7 +56,7 @@

   Delayed::Worker.new(@options).start  
 rescue => e
  •  logger.fatal e
    
  •  Delayed::Worker.logger.fatal e.message if Delayed::Worker.logger
    
    STDERR.puts e.message
    exit 1
    end

undefined method `auto_flushing=' for #<Logger>

I'm trying to get delayed_job running. It seems to fail here:

Delayed::Worker.logger = Rails.logger
Delayed::Worker.logger.auto_flushing = true

My logger doesn't seem to have "auto_flushing".

I'm using

  • Rails 2.3.5
  • ruby 1.8.7 on ubuntu
  • collectiveidea/delayed_job 1.8.4 (per the VERSION file, though I installed it today from github)

Does restarting allow current workers to finish first?

When "script/delayed_job restart production" gets run on a deploy, does it let the existing worker(s) finish or are they killed right away? I'm concerned about a job getting killed in the middle.

By the way, I'm using the daemon-spawn gem. Thanks!
Brian

Mixins on activerecord objects are not available during delayed job execution on rails app

To better explain.
I've got a user model that uses an acts_as plugin that mixes in a certain numer of instance methods to the model.
If I try to run send_later on one of these methods, delayed_job will tell me that method does not exist on the user object, so apparently delayed_job does not load the rails plugins for job execution.
Is there any way around this?

Rake tasks fail with: uninitialized constant Delayed

A quick remedy to the issue above would be to include in project's Rakefile the line:

autoload :Delayed, 'delayed_job'

Another place for the line above could be the delayed/tasks.rb itself. Please, comment on the above.

Replace script/delayed_job with a preforking worker

There are a lot of issues with the existing script for daemonizing delayed_job (each worker runs in its own process, restarts silently fail, logging doesn't work, etc). As Tobi expressed in this thread a unicorn-style preforking worker would be ideal. The master process would be in charge of scheduling jobs (relieving some of the strain on the db), and each worker process would simply be a fork.

I'm still working on wrapping my head around unicorn, but I've started some work on it locally. I'll push what I have if it gets to a point that it's worth sharing. If someone else has time and ambition, then have at it.

TopLevel::Namespace.send_later(:foo) no longer works

I'm not sure why, but it seems like when I use send_later on classes that are located under a module, DJ is not properly enqueuing them.

This is with HEAD, I'll be investigating as this is a major issue for us.

rake jobs:work fails

A recent commit causes rake jobs:work to fail:

jk2:dp jkmiller$ rake jobs:work
(in /Users/james/Sites/rails/dp)
*** Starting job worker host:jk2.local pid:7060
rake aborted!
wrong number of arguments (1 for 0)

script/delayed_job with gem installation

It seems like script/delayed_job is broken for me when I have delayed_job installed as a gem (1.8.4). I get the following error:

script/delayed_job:6:in `require': no such file to load -- script/../vendor/plugins/delayed_job/lib/delayed/command (LoadError)
  from script/delayed_job:6

Do I need to install delayed_job as a plugin in order to use script/delayed_job?

Error when Time.zone is nil

Everything worked fine with 1.8.4.

@@@
>> ActiveRecord::Base.default_timezone
=> :local
>> Time.zone
=> nil

undefined method `now' for nil:NilClass (NoMethodError)
delayed_job-1.8.5/lib/delayed/job.rb:270:in `db_time_now'

Delayed job processing stops forever

I installed DJ in my production machine and everything fine but after a while delayed job processing stops forever. there is no relevant log for that. PID is still remain.
I don't know why and i don't know how to fix that. DJ do critical jobs for me if it execute jobs at their specific "run_at" time.
I need solution that prevent this situation or at least restart DJ automatically when it happen.

starting multiple delayed_jobs via script/delayed_job

being able to start multiple script/delayed_job's would be nice, specifically to allow this:

script/delayed_job start -e Production -n 2 --min-priority 1
script/delayed_job start -e Production -n 8

ie, to be able to have multiple delayed_job processes going, but some have the minimum priority flag set.

I find this desirable behavior. I can do this using rake jobs:work, and something like god, but if I want to use monit I have to use a script like delayed_job because monit doesn't grab and handle pid files like god does.

if you would like to do this, you need to replace the lines:

def daemonize worker_count.times do |worker_index| process_name = worker_count == 1 ? "delayed_job" : "delayed_job.#{worker_index}" Daemons.run_proc(process_name, :dir => "#{RAILS_ROOT}/tmp/pids", :dir_mode => :normal, :ARGV => @args) do |*args| run process_name end end end

with

def daemonize worker_count.times do |worker_index| process_name = "delayed_job_#{@options.zip.join('_')}" process_name += ".#{worker_index}" if worker_count > 1 Daemons.run_proc(process_name, :dir => "#{RAILS_ROOT}/tmp/pids", :dir_mode => :normal, :ARGV => @args, :multiple => true) do |*args| run process_name end end end

thanks,
Adam

MySQL server has gone away

It looks like the delayed_job daemon started by script/delayed_job doesn't try to reconnect to the database. That would be a good idea. Otherwise, once your connection breaks, delayed job processing stops forever.

script/delayed_job ignores environment option

In the process of making script/delayed_job work as a plugin or a gem, I broke the --environment option to the command. Changes in this commit 4d76b8d

To get script/delayed_job to load delayed_job as a plugin or a gem, I had to load config/environment in the script. Only after that does the script load the code to process the arguments, which is then obviously too late to change the RAILS_ENV.

As a current workaround, you can set the RAILS_ENV variable:

RAILS_ENV=production script/delayed_job start

Anyone have any ideas for making it easy for the script to load delayed_job from a plugin or a gem? I could move everything from delayed/command.rb into script/delayed_job, but I'd really prefer to keep all of that logic out of the script since it could potentially change often and users would have to re-run script/generate to get the changes.

script/delayed_job not starting any processes

I am trying to run the following:

script/delayed_job --environment=production start

and no process is ever started and never kicking an error

Ruby Enterprise Edition, Passenger, collectiveidea-delayed_job-1.8.1 vendored as a gem.

Anybody have any other issues?

It works find in dev with just plain script/delayed_job start

Thanks,
~ Tom

"can't convert Array into String" error when using block with Dleayed::Job.enqueue

I'm passing a block into Delayed::Job.enqueue (which according to the source should work). However, I'm getting this error:

can't convert Array into String
/opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.1/lib/delayed/job.rb:268:in `eval'
/opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.1/lib/delayed/job.rb:268:in `perform'
/opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.1/lib/delayed/job.rb:216:in `invoke_job'
/opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/collectiveidea-delayed_job-1.8.1/lib/delayed/job.rb:94:in `run_with_lock'

And here is the code:

class Event < ActiveRecord::Base
  has_many :rosterings
  def send_notifications
    Delayed::Job.enqueue do
      rosterings.unconfirmed.each do |rostering|
        Notifier.deliver_event_rostering_notification(rostering) unless rostering.staff.email.blank?
      end
    end
  end
end

I want the whole block to run as a background process (not just the emails, hence why I haven't used the simpler send_later method which does work).

Any suggestions?

Delayed::Worker.backend = :active_record in plugin causes problems running rake if not using AR

I'm using Mongo as the backend. I have an initializer with:

Delayed::Worker.backend = :mongo

But because the plugin still has the line

Delayed::Worker.backend = :active_record

… it ends up loading ActiveRecord anyway, so when you do "rake test", it fails when trying to look for pending migrations (which of course you don't have 'cuz you're using Mongo)

Commenting out this line in the plugin itself fixes the problem, but that seems like a hackish fix.

You have a nil object when you didn't expect it

Since upgrading I get the following backtrace in "rake jobs:work" and a similar exception when trying to start script/delayed_job:

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.now
.../vendor/plugins/delayed_job/lib/delayed/job.rb:253:in db_time_now' .../vendor/plugins/delayed_job/lib/delayed/job.rb:126:infind_available'
.../vendor/plugins/delayed_job/lib/delayed/job.rb:155:in reserve_and_run_one_job' .../vendor/plugins/delayed_job/lib/delayed/job.rb:202:inwork_off'
.../vendor/plugins/delayed_job/lib/delayed/job.rb:201:in times' .../vendor/plugins/delayed_job/lib/delayed/job.rb:201:inwork_off'
.../vendor/plugins/delayed_job/lib/delayed/worker.rb:30:in start' /usr/lib/ruby/1.8/benchmark.rb:308:inrealtime'
.../vendor/plugins/delayed_job/lib/delayed/worker.rb:29:in start' .../vendor/plugins/delayed_job/lib/delayed/worker.rb:26:inloop'
.../vendor/plugins/delayed_job/lib/delayed/worker.rb:26:in `start'
.../vendor/plugins/delayed_job/lib/delayed/tasks.rb:13

Problems with RAILS_ENV

Guys, inside generators/delayed_job/template/script we have the following code:

#!/usr/bin/env ruby

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'delayed/command'
Delayed::Command.new(ARGV).daemonize

When I do something like ruby script/delayed_job -e production start, the -e option is parsed inside Delayed::Command.new(ARGV). The problem is: the -e option is parsed after the rails environment is loaded, so the code above will always load rails development environment.

I think that's a bug. What do you think?

Add option to log completed jobs

For reporting purposes, some people want to keep completed jobs around.

The only caveat is that we have to get them out of the delayed_jobs table for performance reasons. Apps that queue a lot of jobs will start to suffer quickly if there's hundreds of thousands, or even millions of rows in the jobs table.

I think we should have an optional delayed_job_logs table that records and entry for every job run and statistics about the job (runtime, if it failed, and maybe even server load).

Move all heavy lifting from the Job to the Worker

I'd like to see support for DataMapper and MongoMapper. To do this, all of the logic for performing jobs should be moved to the worker class, and the Job model should simply be a dumb class that knows how to find records and perform the jobs. All of the logic for scheduling and error handling should be in the worker. Then it shouldn't matter what persistence mechanism is used.

Worker name improperly set when using script/delayed_job

The pid is set in the worker name before the daemon splits off the worker processes which means the worker name has the pid of the original process and not the worker process.

I have a fix here
xspond/delayed_job@8f9a321cf6e50617e286398c8f4087a5bf2f781d

undefined method ***** for #<YAML::Object:****>

Hi there,

Here's a bit of code, followed by explanations.

So here's my Job class :

class ImportJobs < Struct.new(:type, :data_file, :user)
  def perform
       Import.tickets(data_file, user) if type == "tickets"
       Import.bl_bre(data_file) if type == "bl"
  end
end

And here's the call :

 Delayed::Job.enqueue(ImportJobs.new(type, data_file, @current_user))

As you can see, I use the ImportJob class to call 2 different methods of the same Import class, depending on the type argument given. The first method doesn't actually get a "data_file" object, it gets an Array, and a "user" object. And it works fine.

BUT, the second function which only gets a "data_file" object fails throwing this error :
"undefined method `path' for #YAML::Object:0x7f16cf40a488" ("path" being a method of my DataFile class)

So I can't manage to figure out why it works when serializing a "user" object, while failing when serializing a "data_file" object.

Obviously, when I call the Import.bl_bre(data_file) method directly (without using DelayedJobs), everythings works well.

Any idea ?

Bug updating failed_at when using mongo backend

I ran into a bug that will only occur when using a mongo backend and configuring the system to not destroy failed jobs. The reschedule method in the worker class called job.update_attribute to update failed_at but mongomapper doesn't support update_attribute. I made the following change and it worked fine:


# self.class.destroy_failed_jobs ? job.destroy : job.update_attribute(:failed_at, Delayed::Job.db_time_now)

if self.class.destroy_failed_jobs
  job.destroy
else
  job.failed_at = Delayed::Job.db_time_now
  job.save
end

Eric

daemon fails to start when delayed_job.log does not exist

The reopen command used to change the log file is not successful if delayed_jog.log does not exist. To correct this add ', "w+"' to the end of line 50 in command.rb:

    @log.reopen File.join(RAILS_ROOT, 'log', 'delayed_job.log'), "w+"

Running delayed jobs on different databases

In my app I switch databases when a request comes in based on the requested url. I was hoping that the delayed job would maintain which database the job was qued in, but it seems that it doesn't. How would you suggest we deal with this? In the app we hijack the database right at the start of the filter chain in application.rb. I was thinking perhaps I'd try to add the database name as an attribute of the model that will be serialised into delayed_job, and then use that to switch the database in my delayed method?

Any ideas would be appreciated :D

Processes dying after a few seconds/minutes

Hi,

On a Debian 5 box, I'm having a strange issue regarding delayed_job processes.
I'm starting them with something like RAILS_ENV=staging script/delayed_job -n 5 start (the problem is the same with only one process)
After a few seconds or minutes, processes are dying, one after another, or all at once.

I've looked into all the log files I could find (deayed_job's own log file, Rails, MySQL, syslog, dmesg, …) and I don't find anything. There is nothing to see in the last_error column in DJ's table.

I've tried to use the regular "daemons" gem or Ghazel's fork, the result is the same.

psand topare not showing anything strange about CPU or MEM for DJ's processes.
The only thing I can see is a single MySQL process that's eating about 100% a a CPU, every oter MySQL processes are sharing the rest.

I'll finish by saying that on my OS X 10.6 laptop, with the exact same DB content and codebase, everything is working perfectly.

I you have any idea, I'd be glad to hear.

Sincerly
Jeremy

Problem with delayed_job_config.rb No works on server

HI.
i have a problem.. when I create this rb file and try to start the server. it get an error message...

destroy_failed_jobs is not a method of Worker

What is the problem?

Dennis Castro.

config/initializers/delayed_job_config.rb

Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_attempts = 3
Delayed::Worker.max_run_time = 5.minutes

if :rails_env cap var is not set, cap delayed_job:start runs in development mode

Not everyone needs to set the :rails_env var in their cap recipe. If :rails_env is not set, delayed_job starts up in development mode.

The workaround is to always set :rails_env in your app's recipe:

set :rails_env, 'production'

The fix for delayed_job is in lib/delayed/recipes.rb - access :rails_env using fetch, and default to 'production':

fetch(:rails_env,'production')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.