Commit e227e0e3d4402574e317db2fd372483a07e8c2ea

Authored by Rodrigo Souto
1 parent d568d8b7

rails3: upgrading delayed_job

Showing 111 changed files with 3703 additions and 2006 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 111 files displayed.

config/initializers/delayed_job_config.rb
  1 +require 'delayed_job'
1 2 Delayed::Worker.backend = :active_record
2 3 Delayed::Worker.max_attempts = 2
3 4 Delayed::Worker.max_run_time = 10.minutes
... ...
db/migrate/20130924152827_add_queue_to_delayed_jobs.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddQueueToDelayedJobs < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :delayed_jobs, :queue, :string
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :delayed_jobs, :queue
  8 + end
  9 +end
... ...
db/schema.rb
1   -# This file is auto-generated from the current state of the database. Instead of editing this file,
2   -# please use the migrations feature of Active Record to incrementally modify your database, and
3   -# then regenerate this schema definition.
  1 +# encoding: UTF-8
  2 +# This file is auto-generated from the current state of the database. Instead
  3 +# of editing this file, please use the migrations feature of Active Record to
  4 +# incrementally modify your database, and then regenerate this schema definition.
4 5 #
5   -# Note that this schema.rb definition is the authoritative source for your database schema. If you need
6   -# to create the application database on another system, you should be using db:schema:load, not running
7   -# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
  6 +# Note that this schema.rb definition is the authoritative source for your
  7 +# database schema. If you need to create the application database on another
  8 +# system, you should be using db:schema:load, not running all the migrations
  9 +# from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 11 #
10 12 # It's strongly recommended to check this file into your version control system.
11 13  
12   -ActiveRecord::Schema.define(:version => 20130606110602) do
  14 +ActiveRecord::Schema.define(:version => 20130924152827) do
13 15  
14 16 create_table "abuse_reports", :force => true do |t|
15 17 t.integer "reporter_id"
... ... @@ -245,6 +247,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130606110602) do
245 247 t.string "locked_by"
246 248 t.datetime "created_at"
247 249 t.datetime "updated_at"
  250 + t.string "queue"
248 251 end
249 252  
250 253 add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
... ...
script/delayed_job
... ... @@ -7,7 +7,5 @@
7 7 # etc. The actual feed update logic is DelayedJob plugin.
8 8  
9 9 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
10   -require 'daemons'
11 10 require 'delayed/command'
12   -
13 11 Delayed::Command.new(ARGV).daemonize
... ...
vendor/plugins/delayed_job/.rspec 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +--color
  2 +--fail-fast
  3 +--order random
... ...
vendor/plugins/delayed_job/.travis.yml 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +language: ruby
  2 +only:
  3 + - master
  4 +rvm:
  5 + - jruby-19mode
  6 + - rbx-19mode
  7 + - 1.9.2
  8 + - 1.9.3
  9 + - 2.0.0
  10 +env:
  11 + matrix:
  12 + - "RAILS_VERSION=\"~> 3.0.0\""
  13 + - "RAILS_VERSION=\"~> 3.1.0\""
  14 + - "RAILS_VERSION=\"~> 3.2.0\""
  15 + - "RAILS_VERSION=\"~> 4.0.0\""
  16 +matrix:
  17 + exclude:
  18 + - rvm: 1.9.2
  19 + env: "RAILS_VERSION=\"~> 4.0.0\""
  20 + allow_failures:
  21 + - rvm: jruby-19mode
  22 + - rvm: rbx-19mode
0 23 \ No newline at end of file
... ...
vendor/plugins/delayed_job/CHANGELOG.md 0 → 100644
... ... @@ -0,0 +1,170 @@
  1 +4.0.0 - 2013-07-30
  2 +==================
  3 +* Rails 4 compatibility
  4 +* Reverted threaded startup due to daemons incompatibilities
  5 +* Attempt to recover from job reservation errors
  6 +
  7 +4.0.0.beta2 - 2013-05-28
  8 +========================
  9 +* Rails 4 compatibility
  10 +* Threaded startup script for faster multi-worker startup
  11 +* YAML compatibility changes
  12 +* Added jobs:check rake task
  13 +
  14 +4.0.0.beta1 - 2013-03-02
  15 +========================
  16 +* Rails 4 compatibility
  17 +
  18 +3.0.5 - 2013-01-28
  19 +==================
  20 +* Better job timeout error logging
  21 +* psych support for delayed_job_data_mapper deserialization
  22 +* User can configure the worker to raise a SignalException on TERM and/or INT
  23 +* Add the ability to run all available jobs and exit when complete
  24 +
  25 +3.0.4 - 2012-11-09
  26 +==================
  27 +* Allow the app to specify a default queue name
  28 +* Capistrano script now allows user to specify the DJ command, allowing the user to add "bundle exec" if necessary
  29 +* Persisted record check is now more general
  30 +
  31 +3.0.3 - 2012-05-25
  32 +==================
  33 +* Fix a bug where the worker would not respect the exit condition
  34 +* Properly handle sleep delay command line argument
  35 +
  36 +3.0.2 - 2012-04-02
  37 +==================
  38 +* Fix deprecation warnings
  39 +* Raise ArgumentError if attempting to enqueue a performable method on an object that hasn't been persisted yet
  40 +* Allow the number of jobs read at a time to be configured from the command line using --read-ahead
  41 +* Allow custom logger to be configured through Delayed::Worker.logger
  42 +* Various documentation improvements
  43 +
  44 +3.0.1 - 2012-01-24
  45 +==================
  46 +* Added RecordNotFound message to deserialization error
  47 +* Direct JRuby's yecht parser to syck extensions
  48 +* Updated psych extensions for better compatibility with ruby 1.9.2
  49 +* Updated syck extension for increased compatibility with class methods
  50 +* Test grooming
  51 +
  52 +3.0.0 - 2011-12-30
  53 +==================
  54 +* New: Named queues
  55 +* New: Job/Worker lifecycle callbacks
  56 +* Change: daemons is no longer a runtime dependency
  57 +* Change: Active Record backend support is provided by a separate gem
  58 +* Change: Enqueue hook is called before jobs are saved so that they may be modified
  59 +* Fix problem deserializing models that use a custom primary key column
  60 +* Fix deserializing AR models when the object isn't in the default scope
  61 +* Fix hooks not getting called when delay_jobs is false
  62 +
  63 +2.1.4 - 2011-02-11
  64 +==================
  65 +* Working around issues when psych is loaded, fixes issues with bundler 1.0.10 and Rails 3.0.4
  66 +* Added -p/--prefix option to help differentiate multiple delayed job workers on the same host.
  67 +
  68 +2.1.3 - 2011-01-20
  69 +==================
  70 +* Revert worker contention fix due to regressions
  71 +* Added Delayed::Worker.delay_jobs flag to support running jobs immediately
  72 +
  73 +2.1.2 - 2010-12-01
  74 +==================
  75 +* Remove contention between multiple workers by performing an update to lock a job before fetching it
  76 +* Job payloads may implement #max_attempts to control how many times it should be retried
  77 +* Fix for loading ActionMailer extension
  78 +* Added 'delayed_job_server_role' Capistrano variable to allow delayed_job to run on its own worker server
  79 + set :delayed_job_server_role, :worker
  80 +* Fix `rake jobs:work` so it outputs to the console
  81 +
  82 +2.1.1 - 2010-11-14
  83 +==================
  84 +* Fix issue with worker name not getting properly set when locking a job
  85 +* Fixes for YAML serialization
  86 +
  87 +2.1.0 - 2010-11-14
  88 +==================
  89 +* Added enqueue, before, after, success, error, and failure. See the README
  90 +* Remove Merb support
  91 +* Remove all non Active Record backends into separate gems. See https://github.com/collectiveidea/delayed_job/wiki/Backends
  92 +* remove rails 2 support. delayed_job 2.1 will only support Rails 3
  93 +* New pure-YAML serialization
  94 +* Added Rails 3 railtie and generator
  95 +* Changed @@sleep_delay to self.class.sleep_delay to be consistent with other class variable usage
  96 +* Added --sleep-delay command line option
  97 +
  98 +2.0.8 - Unreleased
  99 +==================
  100 +* Backport fix for deserialization errors that bring down the daemon
  101 +
  102 +2.0.7 - 2011-02-10
  103 +==================
  104 +* Fixed missing generators and recipes for Rails 2.x
  105 +
  106 +2.0.6 - 2011-01-20
  107 +==================
  108 +* Revert worker contention fix due to regressions
  109 +
  110 +2.0.5 - 2010-12-01
  111 +==================
  112 +* Added #reschedule_at hook on payload to determine when the job should be rescheduled [backported from 2.1]
  113 +* Added --sleep-delay command line option [backported from 2.1]
  114 +* Added 'delayed_job_server_role' Capistrano variable to allow delayed_job to run on its own worker server
  115 + set :delayed_job_server_role, :worker
  116 +* Changed AR backend to reserve jobs using an UPDATE query to reduce worker contention [backported from 2.1]
  117 +
  118 +2.0.4 - 2010-11-14
  119 +==================
  120 +* Fix issue where dirty tracking prevented job from being properly unlocked
  121 +* Add delayed_job_args variable for Capistrano recipe to allow configuration of started workers (e.g. "-n 2 --max-priority 10")
  122 +* Added options to handle_asynchronously
  123 +* Added Delayed::Worker.default_priority
  124 +* Allow private methods to be delayed
  125 +* Fixes for Ruby 1.9
  126 +* Added -m command line option to start a monitor process
  127 +* normalize logging in worker
  128 +* Deprecate #send_later and #send_at in favor of new #delay method
  129 +* Added @#delay@ to Object that allows you to delay any method and pass options:
  130 + options = {:priority => 19, :run_at => 5.minutes.from_now}
  131 + UserMailer.delay(options).deliver_confirmation(@user)
  132 +
  133 +2.0.3 - 2010-04-16
  134 +==================
  135 +* Fix initialization for Rails 2.x
  136 +
  137 +2.0.2 - 2010-04-08
  138 +==================
  139 +* Fixes to Mongo Mapper backend [ "14be7a24":http://github.com/collectiveidea/delayed_job/commit/14be7a24, "dafd5f46":http://github.com/collectiveidea/delayed_job/commit/dafd5f46, "54d40913":http://github.com/collectiveidea/delayed_job/commit/54d40913 ]
  140 +* DataMapper backend performance improvements [ "93833cce":http://github.com/collectiveidea/delayed_job/commit/93833cce, "e9b1573e":http://github.com/collectiveidea/delayed_job/commit/e9b1573e, "37a16d11":http://github.com/collectiveidea/delayed_job/commit/37a16d11, "803f2bfa":http://github.com/collectiveidea/delayed_job/commit/803f2bfa ]
  141 +* Fixed Delayed::Command to create tmp/pids directory [ "8ec8ca41":http://github.com/collectiveidea/delayed_job/commit/8ec8ca41 ]
  142 +* Railtie to perform Rails 3 initialization [ "3e0fc41f":http://github.com/collectiveidea/delayed_job/commit/3e0fc41f ]
  143 +* Added on_permanent_failure hook [ "d2f14cd6":http://github.com/collectiveidea/delayed_job/commit/d2f14cd6 ]
  144 +
  145 +2.0.1 - 2010-04-03
  146 +==================
  147 +* Bug fix for using ActiveRecord backend with daemon [martinbtt]
  148 +
  149 +2.0.0 - 2010-04-03
  150 +==================
  151 +* Multiple backend support (See README for more details)
  152 +* Added MongoMapper backend [zbelzer, moneypools]
  153 +* Added DataMapper backend [lpetre]
  154 +* Reverse priority so the jobs table can be indexed. Lower numbers have higher priority. The default priority is 0, so increase it for jobs that are not important.
  155 +* Move most of the heavy lifting from Job to Worker (#work_off, #reschedule, #run, #min_priority, #max_priority, #max_run_time, #max_attempts, #worker_name) [albus522]
  156 +* Remove EvaledJob. Implement your own if you need this functionality.
  157 +* Only use Time.zone if it is set. Closes #20
  158 +* Fix for last_error recording when destroy_failed_jobs = false, max_attempts = 1
  159 +* Implemented worker name_prefix to maintain dynamic nature of pid detection
  160 +* Some Rails 3 compatibility fixes [fredwu]
  161 +
  162 +1.8.5 - 2010-03-15
  163 +==================
  164 +* Set auto_flushing=true on Rails logger to fix logging in production
  165 +* Fix error message when trying to send_later on a method that doesn't exist
  166 +* Don't use rails_env in capistrano if it's not set. closes #22
  167 +* Delayed job should append to delayed_job.log not overwrite
  168 +* Version bump to 1.8.5
  169 +* fixing Time.now to be Time.zone.now if set to honor the app set local TimeZone
  170 +* Replaced @Worker::SLEEP@, @Job::MAX_ATTEMPTS@, and @Job::MAX_RUN_TIME@ with class methods that can be overridden.
... ...
vendor/plugins/delayed_job/CONTRIBUTING.md 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +How to contribute
  2 +=================
  3 +
  4 +If you find what looks like a bug:
  5 +
  6 +* Search the "mailing list":http://groups.google.com/group/delayed_job to see
  7 + if anyone else had the same issue.
  8 +* Check the "GitHub issue tracker":http://github.com/collectiveidea/delayed_job/issues/
  9 + to see if anyone else has reported issue.
  10 +* Make sure you are using the latest version of delayed_job
  11 + ![Gem Version](https://badge.fury.io/rb/delayed_job.png)
  12 +* Make sure you are using the latest backend gem for delayed_job
  13 + * Active Record ![Gem Version](https://badge.fury.io/rb/delayed_job_active_record.png)
  14 + * Mongoid ![Gem Version](https://badge.fury.io/rb/delayed_job_mongoid.png)
  15 +* If you are still having an issue, create an issue including:
  16 + * Ruby version
  17 + * Gemfile.lock contents or at least major gem versions, such as Rails version
  18 + * Steps to reproduce the issue
  19 + * Full backtrace for any errors encountered
  20 +
  21 +If you want to contribute an enhancement or a fix:
  22 +
  23 +* Fork the project on GitHub.
  24 +* Make your changes with tests.
  25 +* Commit the changes without making changes to the Rakefile or any other files
  26 + that aren't related to your enhancement or fix.
  27 +* Send a pull request.
... ...
vendor/plugins/delayed_job/Gemfile 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +platforms :ruby do
  6 + gem 'sqlite3'
  7 +end
  8 +
  9 +platforms :jruby do
  10 + gem 'jruby-openssl'
  11 + gem 'activerecord-jdbcsqlite3-adapter'
  12 +end
  13 +
  14 +group :test do
  15 + gem 'activerecord', (ENV['RAILS_VERSION'] || ['>= 3.0', '< 4.1'])
  16 + gem 'actionmailer', (ENV['RAILS_VERSION'] || ['>= 3.0', '< 4.1'])
  17 + gem 'coveralls', :require => false
  18 + gem 'rspec', '>= 2.11'
  19 + gem 'simplecov', :require => false
  20 +end
  21 +
  22 +gemspec
... ...
vendor/plugins/delayed_job/LICENSE.md 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +Copyright (c) 2005 Tobias Lütke
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
  17 +NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
... ...
vendor/plugins/delayed_job/MIT-LICENSE
... ... @@ -1,20 +0,0 @@
1   -Copyright (c) 2005 Tobias Luetke
2   -
3   -Permission is hereby granted, free of charge, to any person obtaining
4   -a copy of this software and associated documentation files (the
5   -"Software"), to deal in the Software without restriction, including
6   -without limitation the rights to use, copy, modify, merge, publish,
7   -distribute, sublicense, and/or sell copies of the Software, and to
8   -permit persons to whom the Software is furnished to do so, subject to
9   -the following conditions:
10   -
11   -The above copyright notice and this permission notice shall be
12   -included in all copies or substantial portions of the Software.
13   -
14   -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15   -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16   -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
17   -NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18   -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19   -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20   -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 0 \ No newline at end of file
vendor/plugins/delayed_job/README.md 0 → 100644
... ... @@ -0,0 +1,346 @@
  1 +Delayed::Job
  2 +============
  3 +[![Gem Version](https://badge.fury.io/rb/delayed_job.png)][gem]
  4 +[![Build Status](https://secure.travis-ci.org/collectiveidea/delayed_job.png?branch=master)][travis]
  5 +[![Dependency Status](https://gemnasium.com/collectiveidea/delayed_job.png?travis)][gemnasium]
  6 +[![Code Climate](https://codeclimate.com/github/collectiveidea/delayed_job.png)][codeclimate]
  7 +[![Coverage Status](https://coveralls.io/repos/collectiveidea/delayed_job/badge.png?branch=master)][coveralls]
  8 +
  9 +[gem]: https://rubygems.org/gems/delayed_job
  10 +[travis]: http://travis-ci.org/collectiveidea/delayed_job
  11 +[gemnasium]: https://gemnasium.com/collectiveidea/delayed_job
  12 +[codeclimate]: https://codeclimate.com/github/collectiveidea/delayed_job
  13 +[coveralls]: https://coveralls.io/r/collectiveidea/delayed_job
  14 +
  15 +Delayed::Job (or DJ) encapsulates the common pattern of asynchronously executing
  16 +longer tasks in the background.
  17 +
  18 +It is a direct extraction from Shopify where the job table is responsible for a
  19 +multitude of core tasks. Amongst those tasks are:
  20 +
  21 +* sending massive newsletters
  22 +* image resizing
  23 +* http downloads
  24 +* updating smart collections
  25 +* updating solr, our search server, after product changes
  26 +* batch imports
  27 +* spam checks
  28 +
  29 +[Follow us on Twitter][twitter] to get updates and notices about new releases.
  30 +
  31 +[twitter]: https://twitter.com/delayedjob
  32 +
  33 +Installation
  34 +============
  35 +delayed_job 3.0.0 only supports Rails 3.0+. See the [2.0
  36 +branch](https://github.com/collectiveidea/delayed_job/tree/v2.0) for Rails 2.
  37 +
  38 +delayed_job supports multiple backends for storing the job queue. [See the wiki
  39 +for other backends](http://wiki.github.com/collectiveidea/delayed_job/backends).
  40 +
  41 +If you plan to use delayed_job with Active Record, add `delayed_job_active_record` to your `Gemfile`.
  42 +
  43 +```ruby
  44 +gem 'delayed_job_active_record'
  45 +```
  46 +
  47 +If you plan to use delayed_job with Mongoid, add `delayed_job_mongoid` to your `Gemfile`.
  48 +
  49 +```ruby
  50 +gem 'delayed_job_mongoid'
  51 +```
  52 +
  53 +Run `bundle install` to install the backend and delayed_job gems.
  54 +
  55 +The Active Record backend requires a jobs table. You can create that table by
  56 +running the following command:
  57 +
  58 + rails generate delayed_job:active_record
  59 + rake db:migrate
  60 +
  61 +Rails 4
  62 +=======
  63 +If you are using the protected_attributes gem, it must appear before delayed_job in your gemfile.
  64 +
  65 +Upgrading from 2.x to 3.0.0 on Active Record
  66 +============================================
  67 +Delayed Job 3.0.0 introduces a new column to the delayed_jobs table.
  68 +
  69 +If you're upgrading from Delayed Job 2.x, run the upgrade generator to create a migration to add the column.
  70 +
  71 + rails generate delayed_job:upgrade
  72 + rake db:migrate
  73 +
  74 +Queuing Jobs
  75 +============
  76 +Call `.delay.method(params)` on any object and it will be processed in the background.
  77 +
  78 +```ruby
  79 +# without delayed_job
  80 +@user.activate!(@device)
  81 +
  82 +# with delayed_job
  83 +@user.delay.activate!(@device)
  84 +```
  85 +
  86 +If a method should always be run in the background, you can call
  87 +`#handle_asynchronously` after the method declaration:
  88 +
  89 +```ruby
  90 +class Device
  91 + def deliver
  92 + # long running method
  93 + end
  94 + handle_asynchronously :deliver
  95 +end
  96 +
  97 +device = Device.new
  98 +device.deliver
  99 +```
  100 +
  101 +handle_asynchronously can take as options anything you can pass to delay. In
  102 +addition, the values can be Proc objects allowing call time evaluation of the
  103 +value. For some examples:
  104 +
  105 +```ruby
  106 +class LongTasks
  107 + def send_mailer
  108 + # Some other code
  109 + end
  110 + handle_asynchronously :send_mailer, :priority => 20
  111 +
  112 + def in_the_future
  113 + # Some other code
  114 + end
  115 + # 5.minutes.from_now will be evaluated when in_the_future is called
  116 + handle_asynchronously :in_the_future, :run_at => Proc.new { 5.minutes.from_now }
  117 +
  118 + def self.when_to_run
  119 + 2.hours.from_now
  120 + end
  121 +
  122 + def call_a_class_method
  123 + # Some other code
  124 + end
  125 + handle_asynchronously :call_a_class_method, :run_at => Proc.new { when_to_run }
  126 +
  127 + attr_reader :how_important
  128 +
  129 + def call_an_instance_method
  130 + # Some other code
  131 + end
  132 + handle_asynchronously :call_an_instance_method, :priority => Proc.new {|i| i.how_important }
  133 +end
  134 +```
  135 +
  136 +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`.
  137 +
  138 +Rails 3 Mailers
  139 +===============
  140 +Due to how mailers are implemented in Rails 3, we had to do a little work around to get delayed_job to work.
  141 +
  142 +```ruby
  143 +# without delayed_job
  144 +Notifier.signup(@user).deliver
  145 +
  146 +# with delayed_job
  147 +Notifier.delay.signup(@user)
  148 +```
  149 +
  150 +Remove the `.deliver` method to make it work. It's not ideal, but it's the best
  151 +we could do for now.
  152 +
  153 +Named Queues
  154 +============
  155 +DJ 3 introduces Resque-style named queues while still retaining DJ-style
  156 +priority. The goal is to provide a system for grouping tasks to be worked by
  157 +separate pools of workers, which may be scaled and controlled individually.
  158 +
  159 +Jobs can be assigned to a queue by setting the `queue` option:
  160 +
  161 +```ruby
  162 +object.delay(:queue => 'tracking').method
  163 +
  164 +Delayed::Job.enqueue job, :queue => 'tracking'
  165 +
  166 +handle_asynchronously :tweet_later, :queue => 'tweets'
  167 +```
  168 +
  169 +Running Jobs
  170 +============
  171 +`script/delayed_job` can be used to manage a background process which will
  172 +start working off jobs.
  173 +
  174 +To do so, add `gem "daemons"` to your `Gemfile` and make sure you've run `rails
  175 +generate delayed_job`.
  176 +
  177 +You can then do the following:
  178 +
  179 + RAILS_ENV=production script/delayed_job start
  180 + RAILS_ENV=production script/delayed_job stop
  181 +
  182 + # Runs two workers in separate processes.
  183 + RAILS_ENV=production script/delayed_job -n 2 start
  184 + RAILS_ENV=production script/delayed_job stop
  185 +
  186 + # Set the --queue or --queues option to work from a particular queue.
  187 + RAILS_ENV=production script/delayed_job --queue=tracking start
  188 + RAILS_ENV=production script/delayed_job --queues=mailers,tasks start
  189 +
  190 + # Runs all available jobs and then exits
  191 + RAILS_ENV=production script/delayed_job start --exit-on-complete
  192 + # or to run in the foreground
  193 + RAILS_ENV=production script/delayed_job run --exit-on-complete
  194 +
  195 +**Rails 4:** *replace script/delayed_job with bin/delayed_job*
  196 +
  197 +Workers can be running on any computer, as long as they have access to the
  198 +database and their clock is in sync. Keep in mind that each worker will check
  199 +the database at least every 5 seconds.
  200 +
  201 +You can also invoke `rake jobs:work` which will start working off jobs. You can
  202 +cancel the rake task with `CTRL-C`.
  203 +
  204 +If you want to just run all available jobs and exit you can use `rake jobs:workoff`
  205 +
  206 +Work off queues by setting the `QUEUE` or `QUEUES` environment variable.
  207 +
  208 + QUEUE=tracking rake jobs:work
  209 + QUEUES=mailers,tasks rake jobs:work
  210 +
  211 +Restarting delayed_job
  212 +======================
  213 +
  214 +The following syntax will restart delayed jobs:
  215 +
  216 + RAILS_ENV=production script/delayed_job restart
  217 +
  218 +To restart multiple delayed_job workers:
  219 +
  220 + RAILS_ENV=production script/delayed_job -n2 restart
  221 +
  222 +**Rails 4:** *replace script/delayed_job with bin/delayed_job*
  223 +
  224 +
  225 +
  226 +Custom Jobs
  227 +===========
  228 +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.
  229 +
  230 +```ruby
  231 +class NewsletterJob < Struct.new(:text, :emails)
  232 + def perform
  233 + emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  234 + end
  235 +end
  236 +
  237 +Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
  238 +```
  239 +To set a per-job max attempts that overrides the Delayed::Worker.max_attempts you can define a max_attempts method on the job
  240 +```ruby
  241 +class NewsletterJob < Struct.new(:text, :emails)
  242 + def perform
  243 + emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  244 + end
  245 +
  246 + def max_attempts
  247 + return 3
  248 + end
  249 +end
  250 +````
  251 +
  252 +
  253 +Hooks
  254 +=====
  255 +You can define hooks on your job that will be called at different stages in the process:
  256 +
  257 +```ruby
  258 +class ParanoidNewsletterJob < NewsletterJob
  259 + def enqueue(job)
  260 + record_stat 'newsletter_job/enqueue'
  261 + end
  262 +
  263 + def perform
  264 + emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  265 + end
  266 +
  267 + def before(job)
  268 + record_stat 'newsletter_job/start'
  269 + end
  270 +
  271 + def after(job)
  272 + record_stat 'newsletter_job/after'
  273 + end
  274 +
  275 + def success(job)
  276 + record_stat 'newsletter_job/success'
  277 + end
  278 +
  279 + def error(job, exception)
  280 + Airbrake.notify(exception)
  281 + end
  282 +
  283 + def failure(job)
  284 + page_sysadmin_in_the_middle_of_the_night
  285 + end
  286 +end
  287 +```
  288 +
  289 +Gory Details
  290 +============
  291 +The library revolves around a delayed_jobs table which looks as follows:
  292 +
  293 +```ruby
  294 +create_table :delayed_jobs, :force => true do |table|
  295 + table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
  296 + table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
  297 + table.text :handler # YAML-encoded string of the object that will do work
  298 + table.text :last_error # reason for last failure (See Note below)
  299 + table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
  300 + table.datetime :locked_at # Set when a client is working on this object
  301 + table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
  302 + table.string :locked_by # Who is working on this object (if locked)
  303 + table.string :queue # The name of the queue this job is in
  304 + table.timestamps
  305 +end
  306 +```
  307 +
  308 +On failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.
  309 +
  310 +The default Worker.max_attempts is 25. After this, the job either deleted (default), or left in the database with "failed_at" set.
  311 +With the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.
  312 +
  313 +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
  314 +make sure your job doesn't exceed this time. You should set this to the longest time you think the job could take.
  315 +
  316 +By default, it will delete failed jobs (and it always deletes successful jobs). If you want to keep failed jobs, set
  317 +Delayed::Worker.destroy_failed_jobs = false. The failed jobs will be marked with non-null failed_at.
  318 +
  319 +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.
  320 +
  321 +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.
  322 +
  323 +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.
  324 +
  325 +It is possible to disable delayed jobs for testing purposes. Set Delayed::Worker.delay_jobs = false to execute all jobs realtime.
  326 +
  327 +Here is an example of changing job parameters in Rails:
  328 +
  329 +```ruby
  330 +# config/initializers/delayed_job_config.rb
  331 +Delayed::Worker.destroy_failed_jobs = false
  332 +Delayed::Worker.sleep_delay = 60
  333 +Delayed::Worker.max_attempts = 3
  334 +Delayed::Worker.max_run_time = 5.minutes
  335 +Delayed::Worker.read_ahead = 10
  336 +Delayed::Worker.default_queue_name = 'default'
  337 +Delayed::Worker.delay_jobs = !Rails.env.test?
  338 +```
  339 +
  340 +Cleaning up
  341 +===========
  342 +You can invoke `rake jobs:clear` to delete all jobs in the queue.
  343 +
  344 +Mailing List
  345 +============
  346 +Join us on the [mailing list](http://groups.google.com/group/delayed_job)
... ...
vendor/plugins/delayed_job/README.textile
... ... @@ -1,209 +0,0 @@
1   -h1. Delayed::Job
2   -
3   -Delated_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
4   -
5   -It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:
6   -
7   -* sending massive newsletters
8   -* image resizing
9   -* http downloads
10   -* updating smart collections
11   -* batch imports
12   -* spam checks
13   -
14   -h2. Installation
15   -
16   -To install as a gem, add the following to @config/environment.rb@:
17   -
18   -<pre>
19   -config.gem 'delayed_job'
20   -</pre>
21   -
22   -Rake tasks are not automatically loaded from gems, so you'll need to add the following to your Rakefile:
23   -
24   -<pre>
25   -begin
26   - require 'delayed/tasks'
27   -rescue LoadError
28   - STDERR.puts "Run `rake gems:install` to install delayed_job"
29   -end
30   -</pre>
31   -
32   -To install as a plugin:
33   -
34   -<pre>
35   -script/plugin install git://github.com/collectiveidea/delayed_job.git
36   -</pre>
37   -
38   -After delayed_job is installed, you will need to setup the backend.
39   -
40   -h2. Backends
41   -
42   -delayed_job supports multiple backends for storing the job queue. There are currently implementations for Active Record, MongoMapper, and DataMapper.
43   -
44   -h3. Active Record
45   -
46   -The default is Active Record, which requires a jobs table.
47   -
48   -<pre>
49   -$ script/generate delayed_job
50   -$ rake db:migrate
51   -</pre>
52   -
53   -h3. MongoMapper
54   -
55   -You must use @MongoMapper.setup@ in the initializer:
56   -
57   -<pre>
58   -config = YAML::load(File.read(Rails.root.join('config/mongo.yml')))
59   -MongoMapper.setup(config, Rails.env)
60   -
61   -Delayed::Worker.backend = :mongo_mapper
62   -</pre>
63   -
64   -h3. DataMapper
65   -
66   -<pre>
67   -# config/initializers/delayed_job.rb
68   -Delayed::Worker.backend = :data_mapper
69   -Delayed::Worker.backend.auto_upgrade!
70   -</pre>
71   -
72   -h2. Queuing Jobs
73   -
74   -Call @.delay.method(params)@ on any object and it will be processed in the background.
75   -
76   -<pre>
77   -# without delayed_job
78   -Notifier.deliver_signup(@user)
79   -
80   -# with delayed_job
81   -Notifier.delay.deliver_signup @user
82   -</pre>
83   -
84   -If a method should always be run in the background, you can call @#handle_asynchronously@ after the method declaration:
85   -
86   -<pre>
87   -class Device
88   - def deliver
89   - # long running method
90   - end
91   - handle_asynchronously :deliver
92   -end
93   -
94   -device = Device.new
95   -device.deliver
96   -</pre>
97   -
98   -h2. Running Jobs
99   -
100   -@script/delayed_job@ can be used to manage a background process which will start working off jobs. Make sure you've run `script/generate delayed_job`.
101   -
102   -<pre>
103   -$ RAILS_ENV=production script/delayed_job start
104   -$ RAILS_ENV=production script/delayed_job stop
105   -
106   -# Runs two workers in separate processes.
107   -$ RAILS_ENV=production script/delayed_job -n 2 start
108   -$ RAILS_ENV=production script/delayed_job stop
109   -</pre>
110   -
111   -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.
112   -
113   -You can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@.
114   -
115   -h2. Custom Jobs
116   -
117   -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.
118   -
119   -<pre>
120   -class NewsletterJob < Struct.new(:text, :emails)
121   - def perform
122   - emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
123   - end
124   -end
125   -
126   -Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
127   -</pre>
128   -
129   -You can also add an optional on_permanent_failure method which will run if the job has failed too many times to be retried:
130   -
131   -<pre>
132   -class ParanoidNewsletterJob < NewsletterJob
133   - def perform
134   - emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
135   - end
136   -
137   - def on_permanent_failure
138   - page_sysadmin_in_the_middle_of_the_night
139   - end
140   -end
141   -</pre>
142   -
143   -h2. Gory Details
144   -
145   -The library evolves around a delayed_jobs table which looks as follows:
146   -
147   -<pre>
148   -create_table :delayed_jobs, :force => true do |table|
149   - table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
150   - table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
151   - table.text :handler # YAML-encoded string of the object that will do work
152   - table.text :last_error # reason for last failure (See Note below)
153   - table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
154   - table.datetime :locked_at # Set when a client is working on this object
155   - table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
156   - table.string :locked_by # Who is working on this object (if locked)
157   - table.timestamps
158   -end
159   -</pre>
160   -
161   -On failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.
162   -
163   -The default Worker.max_attempts is 25. After this, the job either deleted (default), or left in the database with "failed_at" set.
164   -With the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.
165   -
166   -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
167   -make sure your job doesn't exceed this time. You should set this to the longest time you think the job could take.
168   -
169   -By default, it will delete failed jobs (and it always deletes successful jobs). If you want to keep failed jobs, set
170   -Delayed::Worker.destroy_failed_jobs = false. The failed jobs will be marked with non-null failed_at.
171   -
172   -Here is an example of changing job parameters in Rails:
173   -
174   -<pre>
175   -# config/initializers/delayed_job_config.rb
176   -Delayed::Worker.destroy_failed_jobs = false
177   -Delayed::Worker.sleep_delay = 60
178   -Delayed::Worker.max_attempts = 3
179   -Delayed::Worker.max_run_time = 5.minutes
180   -</pre>
181   -
182   -h3. Cleaning up
183   -
184   -You can invoke @rake jobs:clear@ to delete all jobs in the queue.
185   -
186   -h2. Mailing List
187   -
188   -Join us on the mailing list at http://groups.google.com/group/delayed_job
189   -
190   -h2. How to contribute
191   -
192   -If you find what looks like a bug:
193   -
194   -# Check the GitHub issue tracker to see if anyone else has had the same issue.
195   - http://github.com/collectiveidea/delayed_job/issues/
196   -# If you don't see anything, create an issue with information on how to reproduce it.
197   -
198   -If you want to contribute an enhancement or a fix:
199   -
200   -# Fork the project on github.
201   - http://github.com/collectiveidea/delayed_job/
202   -# Make your changes with tests.
203   -# Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
204   -# Send a pull request.
205   -
206   -h3. Changelog
207   -
208   -See http://wiki.github.com/collectiveidea/delayed_job/changelog for a list of changes.
209   -
vendor/plugins/delayed_job/Rakefile
1 1 # -*- encoding: utf-8 -*-
2   -begin
3   - require 'jeweler'
4   -rescue LoadError
5   - puts "Jeweler not available. Install it with: sudo gem install jeweler"
6   - exit 1
7   -end
8   -
9   -Jeweler::Tasks.new do |s|
10   - s.name = "delayed_job"
11   - s.summary = "Database-backed asynchronous priority queue system -- Extracted from Shopify"
12   - s.email = "tobi@leetsoft.com"
13   - s.homepage = "http://github.com/collectiveidea/delayed_job"
14   - s.description = "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.\n\nThis gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)."
15   - s.authors = ["Brandon Keepers", "Tobias Lütke"]
16   -
17   - s.has_rdoc = true
18   - s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
19   - s.extra_rdoc_files = ["README.textile"]
20   -
21   - s.test_files = Dir['spec/*_spec.rb']
22   -
23   - s.add_dependency "daemons"
24   - s.add_development_dependency "rspec"
25   - s.add_development_dependency "sqlite3-ruby"
26   - s.add_development_dependency "activerecord"
27   - s.add_development_dependency "mongo_mapper"
28   - s.add_development_dependency "dm-core"
29   - s.add_development_dependency "dm-observer"
30   - s.add_development_dependency "dm-aggregates"
31   - s.add_development_dependency "dm-validations"
32   - s.add_development_dependency "do_sqlite3"
33   - s.add_development_dependency "couchrest"
34   -end
35   -
36   -require 'spec/rake/spectask'
37   -
38   -
39   -task :default do
40   - %w(2.3.5 3.0.0.beta3).each do |version|
41   - puts "Running specs with Rails #{version}"
42   - system("RAILS_VERSION=#{version} rake -s spec;")
43   - end
44   -end
  2 +require 'bundler/setup'
  3 +Bundler::GemHelper.install_tasks
45 4  
  5 +require 'rspec/core/rake_task'
46 6 desc 'Run the specs'
47   -Spec::Rake::SpecTask.new(:spec) do |t|
48   - t.libs << 'lib'
49   - t.pattern = 'spec/*_spec.rb'
50   - t.verbose = true
  7 +RSpec::Core::RakeTask.new do |r|
  8 + r.verbose = false
51 9 end
52   -task :spec => :check_dependencies
53 10  
  11 +task :default => :spec
... ...
vendor/plugins/delayed_job/VERSION
... ... @@ -1 +0,0 @@
1   -2.1.0.pre
vendor/plugins/delayed_job/benchmarks.rb
1   -$:.unshift(File.dirname(__FILE__) + '/lib')
2   -require 'rubygems'
  1 +require 'spec/helper'
3 2 require 'logger'
4   -require 'delayed_job'
5 3 require 'benchmark'
6 4  
7   -RAILS_ENV = 'test'
8   -
9   -Delayed::Worker.logger = Logger.new('/dev/null')
10   -
11   -BACKENDS = []
12   -Dir.glob("#{File.dirname(__FILE__)}/spec/setup/*.rb") do |backend|
13   - begin
14   - backend = File.basename(backend, '.rb')
15   - require "spec/setup/#{backend}"
16   - BACKENDS << backend.to_sym
17   - rescue LoadError
18   - puts "Unable to load #{backend} backend! #{$!}"
19   - end
20   -end
21   -
  5 +# Delayed::Worker.logger = Logger.new('/dev/null')
22 6  
23 7 Benchmark.bm(10) do |x|
24   - BACKENDS.each do |backend|
25   - require "spec/setup/#{backend}"
26   - Delayed::Worker.backend = backend
27   -
28   - n = 10000
29   - n.times { "foo".delay.length }
  8 + Delayed::Job.delete_all
  9 + n = 10000
  10 + n.times { "foo".delay.length }
30 11  
31   - x.report(backend.to_s) { Delayed::Worker.new(:quiet => true).work_off(n) }
32   - end
  12 + x.report { Delayed::Worker.new(:quiet => true).work_off(n) }
33 13 end
... ...
vendor/plugins/delayed_job/contrib/delayed_job.monitrc
... ... @@ -11,4 +11,4 @@
11 11 check process delayed_job
12 12 with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.pid
13 13 start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job start"
14   - stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop"
15 14 \ No newline at end of file
  15 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop"
... ...
vendor/plugins/delayed_job/contrib/delayed_job_multiple.monitrc
... ... @@ -3,21 +3,32 @@
3 3 # To use:
4 4 # 1. copy to /var/www/apps/{app_name}/shared/delayed_job.monitrc
5 5 # 2. replace {app_name} as appropriate
  6 +# you might also need to change the program strings to
  7 +# "/bin/su - {username} -c '/usr/bin/env ...'"
  8 +# to load your shell environment.
  9 +#
6 10 # 3. add this to your /etc/monit/monitrc
7 11 #
8 12 # include /var/www/apps/{app_name}/shared/delayed_job.monitrc
  13 +#
  14 +# The processes are grouped so that monit can act on them as a whole, e.g.
  15 +#
  16 +# monit -g delayed_job restart
9 17  
10 18 check process delayed_job_0
11 19 with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.0.pid
12 20 start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job start -i 0"
13 21 stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop -i 0"
14   -
  22 + group delayed_job
  23 +
15 24 check process delayed_job_1
16 25 with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.1.pid
17 26 start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job start -i 1"
18 27 stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop -i 1"
19   -
  28 + group delayed_job
  29 +
20 30 check process delayed_job_2
21 31 with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.2.pid
22 32 start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job start -i 2"
23   - stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop -i 2"
24 33 \ No newline at end of file
  34 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop -i 2"
  35 + group delayed_job
... ...
vendor/plugins/delayed_job/contrib/delayed_job_rails_4.monitrc 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +# an example Monit configuration file for delayed_job
  2 +# See: http://stackoverflow.com/questions/1226302/how-to-monitor-delayedjob-with-monit/1285611
  3 +#
  4 +# To use:
  5 +# 1. copy to /var/www/apps/{app_name}/shared/delayed_job.monitrc
  6 +# 2. replace {app_name} as appropriate
  7 +# 3. add this to your /etc/monit/monitrc
  8 +#
  9 +# include /var/www/apps/{app_name}/shared/delayed_job.monitrc
  10 +
  11 +check process delayed_job
  12 + with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.pid
  13 + start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job start"
  14 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job stop"
... ...
vendor/plugins/delayed_job/contrib/delayed_job_rails_4_multiple.monitrc 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +# an example Monit configuration file for delayed_job running multiple processes
  2 +#
  3 +# To use:
  4 +# 1. copy to /var/www/apps/{app_name}/shared/delayed_job.monitrc
  5 +# 2. replace {app_name} as appropriate
  6 +# you might also need to change the program strings to
  7 +# "/bin/su - {username} -c '/usr/bin/env ...'"
  8 +# to load your shell environment.
  9 +#
  10 +# 3. add this to your /etc/monit/monitrc
  11 +#
  12 +# include /var/www/apps/{app_name}/shared/delayed_job.monitrc
  13 +#
  14 +# The processes are grouped so that monit can act on them as a whole, e.g.
  15 +#
  16 +# monit -g delayed_job restart
  17 +
  18 +check process delayed_job_0
  19 + with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.0.pid
  20 + start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job start -i 0"
  21 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job stop -i 0"
  22 + group delayed_job
  23 +
  24 +check process delayed_job_1
  25 + with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.1.pid
  26 + start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job start -i 1"
  27 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job stop -i 1"
  28 + group delayed_job
  29 +
  30 +check process delayed_job_2
  31 + with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.2.pid
  32 + start program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job start -i 2"
  33 + stop program = "/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/bin/delayed_job stop -i 2"
  34 + group delayed_job
... ...
vendor/plugins/delayed_job/delayed_job.gemspec
1   -# Generated by jeweler
2   -# DO NOT EDIT THIS FILE DIRECTLY
3   -# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4 1 # -*- encoding: utf-8 -*-
5 2  
6   -Gem::Specification.new do |s|
7   - s.name = %q{delayed_job}
8   - s.version = "2.1.0.pre"
9   -
10   - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11   - s.authors = ["Brandon Keepers", "Tobias L\303\274tke"]
12   - s.date = %q{2010-05-21}
13   - s.description = %q{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.
14   -
15   -This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job).}
16   - s.email = %q{tobi@leetsoft.com}
17   - s.extra_rdoc_files = [
18   - "README.textile"
19   - ]
20   - s.files = [
21   - ".gitignore",
22   - "MIT-LICENSE",
23   - "README.textile",
24   - "Rakefile",
25   - "VERSION",
26   - "benchmarks.rb",
27   - "contrib/delayed_job.monitrc",
28   - "contrib/delayed_job_multiple.monitrc",
29   - "delayed_job.gemspec",
30   - "generators/delayed_job/delayed_job_generator.rb",
31   - "generators/delayed_job/templates/migration.rb",
32   - "generators/delayed_job/templates/script",
33   - "init.rb",
34   - "lib/delayed/backend/active_record.rb",
35   - "lib/delayed/backend/base.rb",
36   - "lib/delayed/backend/couch_rest.rb",
37   - "lib/delayed/backend/data_mapper.rb",
38   - "lib/delayed/backend/mongo_mapper.rb",
39   - "lib/delayed/command.rb",
40   - "lib/delayed/message_sending.rb",
41   - "lib/delayed/performable_method.rb",
42   - "lib/delayed/railtie.rb",
43   - "lib/delayed/recipes.rb",
44   - "lib/delayed/tasks.rb",
45   - "lib/delayed/worker.rb",
46   - "lib/delayed/yaml_ext.rb",
47   - "lib/delayed_job.rb",
48   - "lib/generators/delayed_job/delayed_job_generator.rb",
49   - "lib/generators/delayed_job/templates/migration.rb",
50   - "lib/generators/delayed_job/templates/script",
51   - "rails/init.rb",
52   - "recipes/delayed_job.rb",
53   - "spec/autoloaded/clazz.rb",
54   - "spec/autoloaded/struct.rb",
55   - "spec/backend/active_record_job_spec.rb",
56   - "spec/backend/couch_rest_job_spec.rb",
57   - "spec/backend/data_mapper_job_spec.rb",
58   - "spec/backend/mongo_mapper_job_spec.rb",
59   - "spec/backend/shared_backend_spec.rb",
60   - "spec/message_sending_spec.rb",
61   - "spec/performable_method_spec.rb",
62   - "spec/sample_jobs.rb",
63   - "spec/setup/active_record.rb",
64   - "spec/setup/couch_rest.rb",
65   - "spec/setup/data_mapper.rb",
66   - "spec/setup/mongo_mapper.rb",
67   - "spec/spec_helper.rb",
68   - "spec/worker_spec.rb",
69   - "tasks/jobs.rake"
70   - ]
71   - s.homepage = %q{http://github.com/collectiveidea/delayed_job}
72   - s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
73   - s.require_paths = ["lib"]
74   - s.rubygems_version = %q{1.3.6}
75   - s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}
76   - s.test_files = [
77   - "spec/message_sending_spec.rb",
78   - "spec/performable_method_spec.rb",
79   - "spec/worker_spec.rb"
80   - ]
81   -
82   - if s.respond_to? :specification_version then
83   - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
84   - s.specification_version = 3
85   -
86   - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
87   - s.add_runtime_dependency(%q<daemons>, [">= 0"])
88   - s.add_development_dependency(%q<rspec>, [">= 0"])
89   - s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
90   - s.add_development_dependency(%q<activerecord>, [">= 0"])
91   - s.add_development_dependency(%q<mongo_mapper>, [">= 0"])
92   - s.add_development_dependency(%q<dm-core>, [">= 0"])
93   - s.add_development_dependency(%q<dm-observer>, [">= 0"])
94   - s.add_development_dependency(%q<dm-aggregates>, [">= 0"])
95   - s.add_development_dependency(%q<dm-validations>, [">= 0"])
96   - s.add_development_dependency(%q<do_sqlite3>, [">= 0"])
97   - s.add_development_dependency(%q<couchrest>, [">= 0"])
98   - else
99   - s.add_dependency(%q<daemons>, [">= 0"])
100   - s.add_dependency(%q<rspec>, [">= 0"])
101   - s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
102   - s.add_dependency(%q<activerecord>, [">= 0"])
103   - s.add_dependency(%q<mongo_mapper>, [">= 0"])
104   - s.add_dependency(%q<dm-core>, [">= 0"])
105   - s.add_dependency(%q<dm-observer>, [">= 0"])
106   - s.add_dependency(%q<dm-aggregates>, [">= 0"])
107   - s.add_dependency(%q<dm-validations>, [">= 0"])
108   - s.add_dependency(%q<do_sqlite3>, [">= 0"])
109   - s.add_dependency(%q<couchrest>, [">= 0"])
110   - end
111   - else
112   - s.add_dependency(%q<daemons>, [">= 0"])
113   - s.add_dependency(%q<rspec>, [">= 0"])
114   - s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
115   - s.add_dependency(%q<activerecord>, [">= 0"])
116   - s.add_dependency(%q<mongo_mapper>, [">= 0"])
117   - s.add_dependency(%q<dm-core>, [">= 0"])
118   - s.add_dependency(%q<dm-observer>, [">= 0"])
119   - s.add_dependency(%q<dm-aggregates>, [">= 0"])
120   - s.add_dependency(%q<dm-validations>, [">= 0"])
121   - s.add_dependency(%q<do_sqlite3>, [">= 0"])
122   - s.add_dependency(%q<couchrest>, [">= 0"])
123   - end
  3 +Gem::Specification.new do |spec|
  4 + spec.add_dependency 'activesupport', ['>= 3.0', '< 4.1']
  5 + spec.authors = ["Brandon Keepers", "Brian Ryckbost", "Chris Gaffney", "David Genord II", "Erik Michaels-Ober", "Matt Griffin", "Steve Richert", "Tobias Lütke"]
  6 + spec.description = "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."
  7 + spec.email = ['brian@collectiveidea.com']
  8 + spec.files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile delayed_job.gemspec)
  9 + spec.files += Dir.glob('{contrib,lib,recipes,spec}/**/*')
  10 + spec.homepage = 'http://github.com/collectiveidea/delayed_job'
  11 + spec.licenses = ['MIT']
  12 + spec.name = 'delayed_job'
  13 + spec.require_paths = ['lib']
  14 + spec.summary = 'Database-backed asynchronous priority queue system -- Extracted from Shopify'
  15 + spec.test_files = Dir.glob('spec/**/*')
  16 + spec.version = '4.0.0'
124 17 end
125   -
... ...
vendor/plugins/delayed_job/generators/delayed_job/delayed_job_generator.rb
... ... @@ -1,22 +0,0 @@
1   -class DelayedJobGenerator < Rails::Generator::Base
2   - default_options :skip_migration => false
3   -
4   - def manifest
5   - record do |m|
6   - m.template 'script', 'script/delayed_job', :chmod => 0755
7   - if !options[:skip_migration] && defined?(ActiveRecord)
8   - m.migration_template "migration.rb", 'db/migrate',
9   - :migration_file_name => "create_delayed_jobs"
10   - end
11   - end
12   - end
13   -
14   -protected
15   -
16   - def add_options!(opt)
17   - opt.separator ''
18   - opt.separator 'Options:'
19   - opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
20   - end
21   -
22   -end
vendor/plugins/delayed_job/generators/delayed_job/templates/migration.rb
... ... @@ -1,21 +0,0 @@
1   -class CreateDelayedJobs < ActiveRecord::Migration
2   - def self.up
3   - create_table :delayed_jobs, :force => true do |table|
4   - table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
5   - table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
6   - table.text :handler # YAML-encoded string of the object that will do work
7   - table.text :last_error # reason for last failure (See Note below)
8   - table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9   - table.datetime :locked_at # Set when a client is working on this object
10   - table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11   - table.string :locked_by # Who is working on this object (if locked)
12   - table.timestamps
13   - end
14   -
15   - add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16   - end
17   -
18   - def self.down
19   - drop_table :delayed_jobs
20   - end
21   -end
22 0 \ No newline at end of file
vendor/plugins/delayed_job/init.rb
... ... @@ -1,5 +0,0 @@
1   -require File.join(File.dirname(__FILE__), 'rails', 'init')
2   -
3   -config.after_initialize do
4   - Delayed::Worker.guess_backend
5   -end
vendor/plugins/delayed_job/lib/delayed/backend/active_record.rb
... ... @@ -1,101 +0,0 @@
1   -require 'active_record'
2   -require 'active_record/version'
3   -
4   -class ActiveRecord::Base
5   - yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
6   -
7   - def self.yaml_new(klass, tag, val)
8   - klass.find(val['attributes']['id'])
9   - rescue ActiveRecord::RecordNotFound
10   - nil
11   - end
12   -
13   - def to_yaml_properties
14   - ['@attributes']
15   - end
16   -end
17   -
18   -module Delayed
19   - module Backend
20   - module ActiveRecord
21   - # A job object that is persisted to the database.
22   - # Contains the work object as a YAML field.
23   - class Job < ::ActiveRecord::Base
24   - include Delayed::Backend::Base
25   -
26   - attr_accessible :payload_object, :priority, :run_at
27   -
28   - set_table_name :delayed_jobs
29   -
30   - before_save :set_default_run_at
31   -
32   - if ::ActiveRecord::VERSION::MAJOR >= 3
33   - scope :ready_to_run, lambda {|worker_name, max_run_time|
34   - where(['(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL', db_time_now, db_time_now - max_run_time, worker_name])
35   - }
36   - scope :by_priority, order('priority ASC, run_at ASC')
37   - else
38   - scope :ready_to_run, lambda {|worker_name, max_run_time|
39   - {:conditions => ['(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL', db_time_now, db_time_now - max_run_time, worker_name]}
40   - }
41   - scope :by_priority, :order => 'priority ASC, run_at ASC'
42   - end
43   -
44   - def self.after_fork
45   - ::ActiveRecord::Base.connection.reconnect!
46   - end
47   -
48   - # When a worker is exiting, make sure we don't have any locked jobs.
49   - def self.clear_locks!(worker_name)
50   - update_all("locked_by = null, locked_at = null", ["locked_by = ?", worker_name])
51   - end
52   -
53   - # Find a few candidate jobs to run (in case some immediately get locked by others).
54   - def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
55   - scope = self.ready_to_run(worker_name, max_run_time)
56   - scope = scope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority
57   - scope = scope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority
58   -
59   - ::ActiveRecord::Base.silence do
60   - scope.by_priority.all(:limit => limit)
61   - end
62   - end
63   -
64   - # Lock this job for this worker.
65   - # Returns true if we have the lock, false otherwise.
66   - def lock_exclusively!(max_run_time, worker)
67   - now = self.class.db_time_now
68   - affected_rows = if locked_by != worker
69   - # We don't own this job so we will update the locked_by name and the locked_at
70   - self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?) and (run_at <= ?)", id, (now - max_run_time.to_i), now])
71   - else
72   - # We already own this job, this may happen if the job queue crashes.
73   - # Simply resume and update the locked_at
74   - self.class.update_all(["locked_at = ?", now], ["id = ? and locked_by = ?", id, worker])
75   - end
76   - if affected_rows == 1
77   - self.locked_at = now
78   - self.locked_by = worker
79   - return true
80   - else
81   - return false
82   - end
83   - end
84   -
85   - # Get the current time (GMT or local depending on DB)
86   - # Note: This does not ping the DB to get the time, so all your clients
87   - # must have syncronized clocks.
88   - def self.db_time_now
89   - if Time.zone
90   - Time.zone.now
91   - elsif ::ActiveRecord::Base.default_timezone == :utc
92   - Time.now.utc
93   - else
94   - Time.now
95   - end
96   - end
97   -
98   - end
99   - end
100   - end
101   -end
vendor/plugins/delayed_job/lib/delayed/backend/base.rb
1 1 module Delayed
2 2 module Backend
3   - class DeserializationError < StandardError
4   - end
5   -
6 3 module Base
7 4 def self.included(base)
8 5 base.extend ClassMethods
9 6 end
10   -
  7 +
11 8 module ClassMethods
12 9 # Add a job to the queue
13 10 def enqueue(*args)
14   - object = args.shift
15   - unless object.respond_to?(:perform)
  11 + options = {
  12 + :priority => Delayed::Worker.default_priority,
  13 + :queue => Delayed::Worker.default_queue_name
  14 + }.merge!(args.extract_options!)
  15 +
  16 + options[:payload_object] ||= args.shift
  17 +
  18 + if args.size > 0
  19 + warn "[DEPRECATION] Passing multiple arguments to `#enqueue` is deprecated. Pass a hash with :priority and :run_at."
  20 + options[:priority] = args.first || options[:priority]
  21 + options[:run_at] = args[1]
  22 + end
  23 +
  24 + unless options[:payload_object].respond_to?(:perform)
16 25 raise ArgumentError, 'Cannot enqueue items which do not respond to perform'
17 26 end
18   -
19   - priority = args.first || Delayed::Worker.default_priority
20   - run_at = args[1]
21   - self.create(:payload_object => object, :priority => priority.to_i, :run_at => run_at)
  27 +
  28 + if Delayed::Worker.delay_jobs
  29 + self.new(options).tap do |job|
  30 + Delayed::Worker.lifecycle.run_callbacks(:enqueue, job) do
  31 + job.hook(:enqueue)
  32 + job.save
  33 + end
  34 + end
  35 + else
  36 + Delayed::Job.new(:payload_object => options[:payload_object]).tap do |job|
  37 + job.invoke_job
  38 + end
  39 + end
22 40 end
23   -
  41 +
  42 + def reserve(worker, max_run_time = Worker.max_run_time)
  43 + # We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next.
  44 + # this leads to a more even distribution of jobs across the worker processes
  45 + find_available(worker.name, worker.read_ahead, max_run_time).detect do |job|
  46 + job.lock_exclusively!(max_run_time, worker.name)
  47 + end
  48 + end
  49 +
  50 + # Allow the backend to attempt recovery from reserve errors
  51 + def recover_from(error)
  52 + end
  53 +
24 54 # Hook method that is called before a new worker is forked
25 55 def before_fork
26 56 end
27   -
  57 +
28 58 # Hook method that is called after a new worker is forked
29 59 def after_fork
30 60 end
31   -
  61 +
32 62 def work_off(num = 100)
33 63 warn "[DEPRECATION] `Delayed::Job.work_off` is deprecated. Use `Delayed::Worker.new.work_off instead."
34 64 Delayed::Worker.new.work_off(num)
35 65 end
36 66 end
37   -
38   - ParseObjectFromYaml = /\!ruby\/\w+\:([^\s]+)/
39 67  
40 68 def failed?
41   - failed_at
  69 + !!failed_at
42 70 end
43 71 alias_method :failed, :failed?
44 72  
  73 + ParseObjectFromYaml = /\!ruby\/\w+\:([^\s]+)/
  74 +
45 75 def name
46   - @name ||= begin
47   - payload = payload_object
48   - payload.respond_to?(:display_name) ? payload.display_name : payload.class.name
49   - end
  76 + @name ||= payload_object.respond_to?(:display_name) ?
  77 + payload_object.display_name :
  78 + payload_object.class.name
  79 + rescue DeserializationError
  80 + ParseObjectFromYaml.match(handler)[1]
50 81 end
51 82  
52 83 def payload_object=(object)
  84 + @payload_object = object
53 85 self.handler = object.to_yaml
54 86 end
55   -
  87 +
56 88 def payload_object
57   - @payload_object ||= YAML.load(self.handler)
58   - rescue TypeError, LoadError, NameError => e
59   - raise DeserializationError,
60   - "Job failed to load: #{e.message}. Try to manually require the required file. Handler: #{handler.inspect}"
  89 + if YAML.respond_to?(:unsafe_load)
  90 + #See https://github.com/dtao/safe_yaml
  91 + #When the method is there, we need to load our YAML like this...
  92 + @payload_object ||= YAML.load(self.handler, :safe => false)
  93 + else
  94 + @payload_object ||= YAML.load(self.handler)
  95 + end
  96 + rescue TypeError, LoadError, NameError, ArgumentError => e
  97 + raise DeserializationError,
  98 + "Job failed to load: #{e.message}. Handler: #{handler.inspect}"
61 99 end
62 100  
63   - # Moved into its own method so that new_relic can trace it.
64 101 def invoke_job
65   - payload_object.perform
  102 + Delayed::Worker.lifecycle.run_callbacks(:invoke_job, self) do
  103 + begin
  104 + hook :before
  105 + payload_object.perform
  106 + hook :success
  107 + rescue Exception => e
  108 + hook :error, e
  109 + raise e
  110 + ensure
  111 + hook :after
  112 + end
  113 + end
66 114 end
67   -
  115 +
68 116 # Unlock this job (note: not saved to DB)
69 117 def unlock
70 118 self.locked_at = nil
71 119 self.locked_by = nil
72 120 end
73   -
  121 +
  122 + def hook(name, *args)
  123 + if payload_object.respond_to?(name)
  124 + method = payload_object.method(name)
  125 + method.arity == 0 ? method.call : method.call(self, *args)
  126 + end
  127 + rescue DeserializationError
  128 + # do nothing
  129 + end
  130 +
  131 + def reschedule_at
  132 + payload_object.respond_to?(:reschedule_at) ?
  133 + payload_object.reschedule_at(self.class.db_time_now, attempts) :
  134 + self.class.db_time_now + (attempts ** 4) + 5
  135 + end
  136 +
  137 + def max_attempts
  138 + payload_object.max_attempts if payload_object.respond_to?(:max_attempts)
  139 + end
  140 +
  141 + def fail!
  142 + update_attributes(:failed_at => self.class.db_time_now)
  143 + end
  144 +
74 145 protected
75 146  
76 147 def set_default_run_at
77 148 self.run_at ||= self.class.db_time_now
78 149 end
79   -
  150 +
  151 + # Call during reload operation to clear out internal state
  152 + def reset
  153 + @payload_object = nil
  154 + end
80 155 end
81 156 end
82 157 end
... ...
vendor/plugins/delayed_job/lib/delayed/backend/couch_rest.rb
... ... @@ -1,109 +0,0 @@
1   -require 'couchrest'
2   -
3   -#extent couchrest to handle delayed_job serialization.
4   -class CouchRest::ExtendedDocument
5   - yaml_as "tag:ruby.yaml.org,2002:CouchRest"
6   -
7   - def reload
8   - job = self.class.get self['_id']
9   - job.each {|k,v| self[k] = v}
10   - end
11   - def self.find(id)
12   - get id
13   - end
14   - def self.yaml_new(klass, tag, val)
15   - klass.get(val['_id'])
16   - end
17   - def ==(other)
18   - if other.is_a? ::CouchRest::ExtendedDocument
19   - self['_id'] == other['_id']
20   - else
21   - super
22   - end
23   - end
24   -end
25   -
26   -#couchrest adapter
27   -module Delayed
28   - module Backend
29   - module CouchRest
30   - class Job < ::CouchRest::ExtendedDocument
31   - include Delayed::Backend::Base
32   - use_database ::CouchRest::Server.new.database('delayed_job')
33   -
34   - property :handler
35   - property :last_error
36   - property :locked_by
37   - property :priority, :default => 0
38   - property :attempts, :default => 0
39   - property :run_at, :cast_as => 'Time'
40   - property :locked_at, :cast_as => 'Time'
41   - property :failed_at, :cast_as => 'Time'
42   - timestamps!
43   -
44   - set_callback :save, :before, :set_default_run_at
45   -
46   - view_by(:failed_at, :locked_by, :run_at,
47   - :map => "function(doc){" +
48   - " if(doc['couchrest-type'] == 'Delayed::Backend::CouchRest::Job') {" +
49   - " emit([doc.failed_at || null, doc.locked_by || null, doc.run_at || null], null);}" +
50   - " }")
51   - view_by(:failed_at, :locked_at, :run_at,
52   - :map => "function(doc){" +
53   - " if(doc['couchrest-type'] == 'Delayed::Backend::CouchRest::Job') {" +
54   - " emit([doc.failed_at || null, doc.locked_at || null, doc.run_at || null], null);}" +
55   - " }")
56   -
57   - def self.db_time_now; Time.now; end
58   - def self.find_available(worker_name, limit = 5, max_run_time = ::Delayed::Worker.max_run_time)
59   - ready = ready_jobs
60   - mine = my_jobs worker_name
61   - expire = expired_jobs max_run_time
62   - jobs = (ready + mine + expire)[0..limit-1].sort_by { |j| j.priority }
63   - jobs = jobs.find_all { |j| j.priority >= Worker.min_priority } if Worker.min_priority
64   - jobs = jobs.find_all { |j| j.priority <= Worker.max_priority } if Worker.max_priority
65   - jobs
66   - end
67   - def self.clear_locks!(worker_name)
68   - jobs = my_jobs worker_name
69   - jobs.each { |j| j.locked_by, j.locked_at = nil, nil; }
70   - database.bulk_save jobs
71   - end
72   - def self.delete_all
73   - database.bulk_save all.each { |doc| doc['_deleted'] = true }
74   - end
75   -
76   - def lock_exclusively!(max_run_time, worker = worker_name)
77   - return false if locked_by_other?(worker) and not expired?(max_run_time)
78   - case
79   - when locked_by_me?(worker)
80   - self.locked_at = self.class.db_time_now
81   - when (unlocked? or (locked_by_other?(worker) and expired?(max_run_time)))
82   - self.locked_at, self.locked_by = self.class.db_time_now, worker
83   - end
84   - save
85   - rescue RestClient::Conflict
86   - false
87   - end
88   -
89   - private
90   - def self.ready_jobs
91   - options = {:startkey => [nil, nil], :endkey => [nil, nil, db_time_now]}
92   - by_failed_at_and_locked_by_and_run_at options
93   - end
94   - def self.my_jobs(worker_name)
95   - options = {:startkey => [nil, worker_name], :endkey => [nil, worker_name, {}]}
96   - by_failed_at_and_locked_by_and_run_at options
97   - end
98   - def self.expired_jobs(max_run_time)
99   - options = {:startkey => [nil,'0'], :endkey => [nil, db_time_now - max_run_time, db_time_now]}
100   - by_failed_at_and_locked_at_and_run_at options
101   - end
102   - def unlocked?; locked_by.nil?; end
103   - def expired?(time); locked_at < self.class.db_time_now - time; end
104   - def locked_by_me?(worker); not locked_by.nil? and locked_by == worker; end
105   - def locked_by_other?(worker); not locked_by.nil? and locked_by != worker; end
106   - end
107   - end
108   - end
109   -end
vendor/plugins/delayed_job/lib/delayed/backend/data_mapper.rb
... ... @@ -1,121 +0,0 @@
1   -require 'dm-core'
2   -require 'dm-observer'
3   -require 'dm-aggregates'
4   -
5   -DataMapper::Resource.class_eval do
6   - yaml_as "tag:ruby.yaml.org,2002:DataMapper"
7   -
8   - def self.yaml_new(klass, tag, val)
9   - klass.find(val['id'])
10   - end
11   -
12   - def to_yaml_properties
13   - ['@id']
14   - end
15   -end
16   -
17   -module Delayed
18   - module Backend
19   - module DataMapper
20   - class Job
21   - include ::DataMapper::Resource
22   - include Delayed::Backend::Base
23   -
24   - storage_names[:default] = 'delayed_jobs'
25   -
26   - property :id, Serial
27   - property :priority, Integer, :default => 0, :index => :run_at_priority
28   - property :attempts, Integer, :default => 0
29   - property :handler, Text, :lazy => false
30   - property :run_at, Time, :index => :run_at_priority
31   - property :locked_at, Time, :index => true
32   - property :locked_by, String
33   - property :failed_at, Time
34   - property :last_error, Text
35   -
36   - def self.db_time_now
37   - Time.now
38   - end
39   -
40   - def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
41   -
42   - simple_conditions = { :run_at.lte => db_time_now, :limit => limit, :failed_at => nil, :order => [:priority.asc, :run_at.asc] }
43   -
44   - # respect priorities
45   - simple_conditions[:priority.gte] = Worker.min_priority if Worker.min_priority
46   - simple_conditions[:priority.lte] = Worker.max_priority if Worker.max_priority
47   -
48   - # lockable
49   - lockable = (
50   - # not locked or past the max time
51   - ( all(:locked_at => nil ) | all(:locked_at.lt => db_time_now - max_run_time)) |
52   -
53   - # OR locked by our worker
54   - all(:locked_by => worker_name))
55   -
56   - # plus some other boring junk
57   - (lockable).all( simple_conditions )
58   - end
59   -
60   - # When a worker is exiting, make sure we don't have any locked jobs.
61   - def self.clear_locks!(worker_name)
62   - all(:locked_by => worker_name).update(:locked_at => nil, :locked_by => nil)
63   - end
64   -
65   - # Lock this job for this worker.
66   - # Returns true if we have the lock, false otherwise.
67   - def lock_exclusively!(max_run_time, worker = worker_name)
68   -
69   - now = self.class.db_time_now
70   - overtime = now - max_run_time
71   -
72   - # FIXME - this is a bit gross
73   - # DM doesn't give us the number of rows affected by a collection update
74   - # so we have to circumvent some niceness in DM::Collection here
75   - collection = locked_by != worker ?
76   - (self.class.all(:id => id, :run_at.lte => now) & ( self.class.all(:locked_at => nil) | self.class.all(:locked_at.lt => overtime) ) ) :
77   - self.class.all(:id => id, :locked_by => worker)
78   -
79   - attributes = collection.model.new(:locked_at => now, :locked_by => worker).dirty_attributes
80   - affected_rows = self.repository.update(attributes, collection)
81   -
82   - if affected_rows == 1
83   - self.locked_at = now
84   - self.locked_by = worker
85   - return true
86   - else
87   - return false
88   - end
89   - end
90   -
91   - # these are common to the other backends, so we provide an implementation
92   - def self.delete_all
93   - Delayed::Job.auto_migrate!
94   - end
95   -
96   - def self.find id
97   - get id
98   - end
99   -
100   - def update_attributes(attributes)
101   - attributes.each do |k,v|
102   - self[k] = v
103   - end
104   - self.save
105   - end
106   -
107   -
108   - end
109   -
110   - class JobObserver
111   - include ::DataMapper::Observer
112   -
113   - observe Job
114   -
115   - before :save do
116   - self.run_at ||= self.class.db_time_now
117   - end
118   - end
119   - end
120   - end
121   -end
vendor/plugins/delayed_job/lib/delayed/backend/mongo_mapper.rb
... ... @@ -1,106 +0,0 @@
1   -require 'mongo_mapper'
2   -
3   -MongoMapper::Document.class_eval do
4   - yaml_as "tag:ruby.yaml.org,2002:MongoMapper"
5   -
6   - def self.yaml_new(klass, tag, val)
7   - klass.find(val['_id'])
8   - end
9   -
10   - def to_yaml_properties
11   - ['@_id']
12   - end
13   -end
14   -
15   -module Delayed
16   - module Backend
17   - module MongoMapper
18   - class Job
19   - include ::MongoMapper::Document
20   - include Delayed::Backend::Base
21   - set_collection_name 'delayed_jobs'
22   -
23   - key :priority, Integer, :default => 0
24   - key :attempts, Integer, :default => 0
25   - key :handler, String
26   - key :run_at, Time
27   - key :locked_at, Time
28   - key :locked_by, String, :index => true
29   - key :failed_at, Time
30   - key :last_error, String
31   - timestamps!
32   -
33   - before_save :set_default_run_at
34   -
35   - ensure_index [[:priority, 1], [:run_at, 1]]
36   -
37   - def self.before_fork
38   - ::MongoMapper.connection.close
39   - end
40   -
41   - def self.after_fork
42   - ::MongoMapper.connect(RAILS_ENV)
43   - end
44   -
45   - def self.db_time_now
46   - Time.now.utc
47   - end
48   -
49   - def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
50   - right_now = db_time_now
51   -
52   - conditions = {
53   - :run_at => {"$lte" => right_now},
54   - :limit => -limit, # In mongo, positive limits are 'soft' and negative are 'hard'
55   - :failed_at => nil,
56   - :sort => [['priority', 1], ['run_at', 1]]
57   - }
58   -
59   - where = "this.locked_at == null || this.locked_at < #{make_date(right_now - max_run_time)}"
60   -
61   - (conditions[:priority] ||= {})['$gte'] = Worker.min_priority.to_i if Worker.min_priority
62   - (conditions[:priority] ||= {})['$lte'] = Worker.max_priority.to_i if Worker.max_priority
63   -
64   - results = all(conditions.merge(:locked_by => worker_name))
65   - results += all(conditions.merge('$where' => where)) if results.size < limit
66   - results
67   - end
68   -
69   - # When a worker is exiting, make sure we don't have any locked jobs.
70   - def self.clear_locks!(worker_name)
71   - collection.update({:locked_by => worker_name}, {"$set" => {:locked_at => nil, :locked_by => nil}}, :multi => true)
72   - end
73   -
74   - # Lock this job for this worker.
75   - # Returns true if we have the lock, false otherwise.
76   - def lock_exclusively!(max_run_time, worker = worker_name)
77   - right_now = self.class.db_time_now
78   - overtime = right_now - max_run_time.to_i
79   -
80   - query = "this.locked_at == null || this.locked_at < #{make_date(overtime)} || this.locked_by == #{worker.to_json}"
81   - conditions = {:_id => id, :run_at => {"$lte" => right_now}, "$where" => query}
82   -
83   - collection.update(conditions, {"$set" => {:locked_at => right_now, :locked_by => worker}})
84   - affected_rows = collection.find({:_id => id, :locked_by => worker}).count
85   - if affected_rows == 1
86   - self.locked_at = right_now
87   - self.locked_by = worker
88   - return true
89   - else
90   - return false
91   - end
92   - end
93   -
94   - private
95   -
96   - def self.make_date(date_or_seconds)
97   - "new Date(#{date_or_seconds.to_f * 1000})"
98   - end
99   -
100   - def make_date(date)
101   - self.class.make_date(date)
102   - end
103   - end
104   - end
105   - end
106   -end
vendor/plugins/delayed_job/lib/delayed/backend/shared_spec.rb 0 → 100644
... ... @@ -0,0 +1,594 @@
  1 +require File.expand_path('../../../../spec/sample_jobs', __FILE__)
  2 +
  3 +require 'active_support/core_ext'
  4 +
  5 +shared_examples_for "a delayed_job backend" do
  6 + let(:worker) { Delayed::Worker.new }
  7 +
  8 + def create_job(opts = {})
  9 + described_class.create(opts.merge(:payload_object => SimpleJob.new))
  10 + end
  11 +
  12 + before do
  13 + Delayed::Worker.max_priority = nil
  14 + Delayed::Worker.min_priority = nil
  15 + Delayed::Worker.default_priority = 99
  16 + Delayed::Worker.delay_jobs = true
  17 + SimpleJob.runs = 0
  18 + described_class.delete_all
  19 + end
  20 +
  21 + after do
  22 + Delayed::Worker.reset
  23 + end
  24 +
  25 + it "sets run_at automatically if not set" do
  26 + expect(described_class.create(:payload_object => ErrorJob.new ).run_at).not_to be_nil
  27 + end
  28 +
  29 + it "does not set run_at automatically if already set" do
  30 + later = described_class.db_time_now + 5.minutes
  31 + job = described_class.create(:payload_object => ErrorJob.new, :run_at => later)
  32 + expect(job.run_at).to be_within(1).of(later)
  33 + end
  34 +
  35 + describe "#reload" do
  36 + it "reloads the payload" do
  37 + job = described_class.enqueue :payload_object => SimpleJob.new
  38 + expect(job.payload_object.object_id).not_to eq(job.reload.payload_object.object_id)
  39 + end
  40 + end
  41 +
  42 + describe "enqueue" do
  43 + context "with a hash" do
  44 + it "raises ArgumentError when handler doesn't respond_to :perform" do
  45 + expect{described_class.enqueue(:payload_object => Object.new)}.to raise_error(ArgumentError)
  46 + end
  47 +
  48 + it "is able to set priority" do
  49 + job = described_class.enqueue :payload_object => SimpleJob.new, :priority => 5
  50 + expect(job.priority).to eq(5)
  51 + end
  52 +
  53 + it "uses default priority" do
  54 + job = described_class.enqueue :payload_object => SimpleJob.new
  55 + expect(job.priority).to eq(99)
  56 + end
  57 +
  58 + it "is able to set run_at" do
  59 + later = described_class.db_time_now + 5.minutes
  60 + job = described_class.enqueue :payload_object => SimpleJob.new, :run_at => later
  61 + expect(job.run_at).to be_within(1).of(later)
  62 + end
  63 +
  64 + it "is able to set queue" do
  65 + job = described_class.enqueue :payload_object => SimpleJob.new, :queue => 'tracking'
  66 + expect(job.queue).to eq('tracking')
  67 + end
  68 + end
  69 +
  70 + context "with multiple arguments" do
  71 + it "raises ArgumentError when handler doesn't respond_to :perform" do
  72 + expect{described_class.enqueue(Object.new)}.to raise_error(ArgumentError)
  73 + end
  74 +
  75 + it "increases count after enqueuing items" do
  76 + described_class.enqueue SimpleJob.new
  77 + expect(described_class.count).to eq(1)
  78 + end
  79 +
  80 + it "is able to set priority [DEPRECATED]" do
  81 + silence_warnings do
  82 + job = described_class.enqueue SimpleJob.new, 5
  83 + expect(job.priority).to eq(5)
  84 + end
  85 + end
  86 +
  87 + it "uses default priority when it is not set" do
  88 + @job = described_class.enqueue SimpleJob.new
  89 + expect(@job.priority).to eq(99)
  90 + end
  91 +
  92 + it "is able to set run_at [DEPRECATED]" do
  93 + silence_warnings do
  94 + later = described_class.db_time_now + 5.minutes
  95 + @job = described_class.enqueue SimpleJob.new, 5, later
  96 + expect(@job.run_at).to be_within(1).of(later)
  97 + end
  98 + end
  99 +
  100 + it "works with jobs in modules" do
  101 + M::ModuleJob.runs = 0
  102 + job = described_class.enqueue M::ModuleJob.new
  103 + expect{job.invoke_job}.to change { M::ModuleJob.runs }.from(0).to(1)
  104 + end
  105 + end
  106 +
  107 + context "with delay_jobs = false" do
  108 + before(:each) do
  109 + Delayed::Worker.delay_jobs = false
  110 + end
  111 +
  112 + it "does not increase count after enqueuing items" do
  113 + described_class.enqueue SimpleJob.new
  114 + expect(described_class.count).to eq(0)
  115 + end
  116 +
  117 + it "invokes the enqueued job" do
  118 + job = SimpleJob.new
  119 + job.should_receive(:perform)
  120 + described_class.enqueue job
  121 + end
  122 +
  123 + it "returns a job, not the result of invocation" do
  124 + expect(described_class.enqueue(SimpleJob.new)).to be_instance_of(described_class)
  125 + end
  126 + end
  127 + end
  128 +
  129 + describe "callbacks" do
  130 + before(:each) do
  131 + CallbackJob.messages = []
  132 + end
  133 +
  134 + %w(before success after).each do |callback|
  135 + it "calls #{callback} with job" do
  136 + job = described_class.enqueue(CallbackJob.new)
  137 + job.payload_object.should_receive(callback).with(job)
  138 + job.invoke_job
  139 + end
  140 + end
  141 +
  142 + it "calls before and after callbacks" do
  143 + job = described_class.enqueue(CallbackJob.new)
  144 + expect(CallbackJob.messages).to eq(["enqueue"])
  145 + job.invoke_job
  146 + expect(CallbackJob.messages).to eq(["enqueue", "before", "perform", "success", "after"])
  147 + end
  148 +
  149 + it "calls the after callback with an error" do
  150 + job = described_class.enqueue(CallbackJob.new)
  151 + job.payload_object.should_receive(:perform).and_raise(RuntimeError.new("fail"))
  152 +
  153 + expect{job.invoke_job}.to raise_error
  154 + expect(CallbackJob.messages).to eq(["enqueue", "before", "error: RuntimeError", "after"])
  155 + end
  156 +
  157 + it "calls error when before raises an error" do
  158 + job = described_class.enqueue(CallbackJob.new)
  159 + job.payload_object.should_receive(:before).and_raise(RuntimeError.new("fail"))
  160 + expect{job.invoke_job}.to raise_error(RuntimeError)
  161 + expect(CallbackJob.messages).to eq(["enqueue", "error: RuntimeError", "after"])
  162 + end
  163 + end
  164 +
  165 + describe "payload_object" do
  166 + it "raises a DeserializationError when the job class is totally unknown" do
  167 + job = described_class.new :handler => "--- !ruby/object:JobThatDoesNotExist {}"
  168 + expect{job.payload_object}.to raise_error(Delayed::DeserializationError)
  169 + end
  170 +
  171 + it "raises a DeserializationError when the job struct is totally unknown" do
  172 + job = described_class.new :handler => "--- !ruby/struct:StructThatDoesNotExist {}"
  173 + expect{job.payload_object}.to raise_error(Delayed::DeserializationError)
  174 + end
  175 +
  176 + it "raises a DeserializationError when the YAML.load raises argument error" do
  177 + job = described_class.new :handler => "--- !ruby/struct:GoingToRaiseArgError {}"
  178 + YAML.should_receive(:load).and_raise(ArgumentError)
  179 + expect{job.payload_object}.to raise_error(Delayed::DeserializationError)
  180 + end
  181 + end
  182 +
  183 + describe "reserve" do
  184 + before do
  185 + Delayed::Worker.max_run_time = 2.minutes
  186 + end
  187 +
  188 + after do
  189 + Time.zone = nil
  190 + end
  191 +
  192 + it "does not reserve failed jobs" do
  193 + create_job :attempts => 50, :failed_at => described_class.db_time_now
  194 + expect(described_class.reserve(worker)).to be_nil
  195 + end
  196 +
  197 + it "does not reserve jobs scheduled for the future" do
  198 + create_job :run_at => described_class.db_time_now + 1.minute
  199 + expect(described_class.reserve(worker)).to be_nil
  200 + end
  201 +
  202 + it "reserves jobs scheduled for the past" do
  203 + job = create_job :run_at => described_class.db_time_now - 1.minute
  204 + expect(described_class.reserve(worker)).to eq(job)
  205 + end
  206 +
  207 + it "reserves jobs scheduled for the past when time zones are involved" do
  208 + Time.zone = 'US/Eastern'
  209 + job = create_job :run_at => described_class.db_time_now - 1.minute
  210 + expect(described_class.reserve(worker)).to eq(job)
  211 + end
  212 +
  213 + it "does not reserve jobs locked by other workers" do
  214 + job = create_job
  215 + other_worker = Delayed::Worker.new
  216 + other_worker.name = 'other_worker'
  217 + expect(described_class.reserve(other_worker)).to eq(job)
  218 + expect(described_class.reserve(worker)).to be_nil
  219 + end
  220 +
  221 + it "reserves open jobs" do
  222 + job = create_job
  223 + expect(described_class.reserve(worker)).to eq(job)
  224 + end
  225 +
  226 + it "reserves expired jobs" do
  227 + job = create_job(:locked_by => 'some other worker', :locked_at => described_class.db_time_now - Delayed::Worker.max_run_time - 1.minute)
  228 + expect(described_class.reserve(worker)).to eq(job)
  229 + end
  230 +
  231 + it "reserves own jobs" do
  232 + job = create_job(:locked_by => worker.name, :locked_at => (described_class.db_time_now - 1.minutes))
  233 + expect(described_class.reserve(worker)).to eq(job)
  234 + end
  235 + end
  236 +
  237 + context "#name" do
  238 + it "is the class name of the job that was enqueued" do
  239 + expect(described_class.create(:payload_object => ErrorJob.new ).name).to eq('ErrorJob')
  240 + end
  241 +
  242 + it "is the method that will be called if its a performable method object" do
  243 + job = described_class.new(:payload_object => NamedJob.new)
  244 + expect(job.name).to eq('named_job')
  245 + end
  246 +
  247 + it "is the instance method that will be called if its a performable method object" do
  248 + job = Story.create(:text => "...").delay.save
  249 + expect(job.name).to eq('Story#save')
  250 + end
  251 +
  252 + it "parses from handler on deserialization error" do
  253 + job = Story.create(:text => "...").delay.text
  254 + job.payload_object.object.destroy
  255 + expect(job.reload.name).to eq('Delayed::PerformableMethod')
  256 + end
  257 + end
  258 +
  259 + context "worker prioritization" do
  260 + after do
  261 + Delayed::Worker.max_priority = nil
  262 + Delayed::Worker.min_priority = nil
  263 + end
  264 +
  265 + it "fetches jobs ordered by priority" do
  266 + 10.times { described_class.enqueue SimpleJob.new, :priority => rand(10) }
  267 + jobs = []
  268 + 10.times { jobs << described_class.reserve(worker) }
  269 + expect(jobs.size).to eq(10)
  270 + jobs.each_cons(2) do |a, b|
  271 + expect(a.priority).to be <= b.priority
  272 + end
  273 + end
  274 +
  275 + it "only finds jobs greater than or equal to min priority" do
  276 + min = 5
  277 + Delayed::Worker.min_priority = min
  278 + [4,5,6].sort_by {|i| rand }.each {|i| create_job :priority => i }
  279 + 2.times do
  280 + job = described_class.reserve(worker)
  281 + expect(job.priority).to be >= min
  282 + job.destroy
  283 + end
  284 + expect(described_class.reserve(worker)).to be_nil
  285 + end
  286 +
  287 + it "only finds jobs less than or equal to max priority" do
  288 + max = 5
  289 + Delayed::Worker.max_priority = max
  290 + [4,5,6].sort_by {|i| rand }.each {|i| create_job :priority => i }
  291 + 2.times do
  292 + job = described_class.reserve(worker)
  293 + expect(job.priority).to be <= max
  294 + job.destroy
  295 + end
  296 + expect(described_class.reserve(worker)).to be_nil
  297 + end
  298 + end
  299 +
  300 + context "clear_locks!" do
  301 + before do
  302 + @job = create_job(:locked_by => 'worker1', :locked_at => described_class.db_time_now)
  303 + end
  304 +
  305 + it "clears locks for the given worker" do
  306 + described_class.clear_locks!('worker1')
  307 + expect(described_class.reserve(worker)).to eq(@job)
  308 + end
  309 +
  310 + it "does not clear locks for other workers" do
  311 + described_class.clear_locks!('different_worker')
  312 + expect(described_class.reserve(worker)).not_to eq(@job)
  313 + end
  314 + end
  315 +
  316 + context "unlock" do
  317 + before do
  318 + @job = create_job(:locked_by => 'worker', :locked_at => described_class.db_time_now)
  319 + end
  320 +
  321 + it "clears locks" do
  322 + @job.unlock
  323 + expect(@job.locked_by).to be_nil
  324 + expect(@job.locked_at).to be_nil
  325 + end
  326 + end
  327 +
  328 + context "large handler" do
  329 + before do
  330 + text = "Lorem ipsum dolor sit amet. " * 1000
  331 + @job = described_class.enqueue Delayed::PerformableMethod.new(text, :length, {})
  332 + end
  333 +
  334 + it "has an id" do
  335 + expect(@job.id).not_to be_nil
  336 + end
  337 + end
  338 +
  339 + context "named queues" do
  340 + context "when worker has one queue set" do
  341 + before(:each) do
  342 + worker.queues = ['large']
  343 + end
  344 +
  345 + it "only works off jobs which are from its queue" do
  346 + expect(SimpleJob.runs).to eq(0)
  347 +
  348 + create_job(:queue => "large")
  349 + create_job(:queue => "small")
  350 + worker.work_off
  351 +
  352 + expect(SimpleJob.runs).to eq(1)
  353 + end
  354 + end
  355 +
  356 + context "when worker has two queue set" do
  357 + before(:each) do
  358 + worker.queues = ['large', 'small']
  359 + end
  360 +
  361 + it "only works off jobs which are from its queue" do
  362 + expect(SimpleJob.runs).to eq(0)
  363 +
  364 + create_job(:queue => "large")
  365 + create_job(:queue => "small")
  366 + create_job(:queue => "medium")
  367 + create_job
  368 + worker.work_off
  369 +
  370 + expect(SimpleJob.runs).to eq(2)
  371 + end
  372 + end
  373 +
  374 + context "when worker does not have queue set" do
  375 + before(:each) do
  376 + worker.queues = []
  377 + end
  378 +
  379 + it "works off all jobs" do
  380 + expect(SimpleJob.runs).to eq(0)
  381 +
  382 + create_job(:queue => "one")
  383 + create_job(:queue => "two")
  384 + create_job
  385 + worker.work_off
  386 +
  387 + expect(SimpleJob.runs).to eq(3)
  388 + end
  389 + end
  390 + end
  391 +
  392 + context "max_attempts" do
  393 + before(:each) do
  394 + @job = described_class.enqueue SimpleJob.new
  395 + end
  396 +
  397 + it "is not defined" do
  398 + expect(@job.max_attempts).to be_nil
  399 + end
  400 +
  401 + it "uses the max_retries value on the payload when defined" do
  402 + @job.payload_object.stub(:max_attempts).and_return(99)
  403 + expect(@job.max_attempts).to eq(99)
  404 + end
  405 + end
  406 +
  407 + describe "yaml serialization" do
  408 + it "reloads changed attributes" do
  409 + story = Story.create(:text => 'hello')
  410 + job = story.delay.tell
  411 + story.update_attributes :text => 'goodbye'
  412 + expect(job.reload.payload_object.object.text).to eq('goodbye')
  413 + end
  414 +
  415 + it "raises error ArgumentError the record is not persisted" do
  416 + story = Story.new(:text => 'hello')
  417 + if story.respond_to?(:new_record?)
  418 + expect {
  419 + story.delay.tell
  420 + }.to raise_error(ArgumentError, "Jobs cannot be created for records before they've been persisted")
  421 + end
  422 + end
  423 +
  424 + it "raises deserialization error for destroyed records" do
  425 + story = Story.create(:text => 'hello')
  426 + job = story.delay.tell
  427 + story.destroy
  428 + expect {
  429 + job.reload.payload_object
  430 + }.to raise_error(Delayed::DeserializationError)
  431 + end
  432 + end
  433 +
  434 + describe "worker integration" do
  435 + before do
  436 + Delayed::Job.delete_all
  437 + SimpleJob.runs = 0
  438 + end
  439 +
  440 + describe "running a job" do
  441 + it "fails after Worker.max_run_time" do
  442 + Delayed::Worker.max_run_time = 1.second
  443 + job = Delayed::Job.create :payload_object => LongRunningJob.new
  444 + worker.run(job)
  445 + expect(job.reload.last_error).to match(/expired/)
  446 + expect(job.reload.last_error).to match(/Delayed::Worker.max_run_time is only 1 second/)
  447 + expect(job.attempts).to eq(1)
  448 + end
  449 +
  450 + context "when the job raises a deserialization error" do
  451 + after do
  452 + Delayed::Worker.destroy_failed_jobs = true
  453 + end
  454 +
  455 + it "marks the job as failed" do
  456 + Delayed::Worker.destroy_failed_jobs = false
  457 + job = described_class.create! :handler => "--- !ruby/object:JobThatDoesNotExist {}"
  458 + worker.work_off
  459 + job.reload
  460 + expect(job).to be_failed
  461 + end
  462 + end
  463 + end
  464 +
  465 + describe "failed jobs" do
  466 + before do
  467 + @job = Delayed::Job.enqueue(ErrorJob.new, :run_at => described_class.db_time_now - 1)
  468 + end
  469 +
  470 + after do
  471 + # reset default
  472 + Delayed::Worker.destroy_failed_jobs = true
  473 + end
  474 +
  475 + it "records last_error when destroy_failed_jobs = false, max_attempts = 1" do
  476 + Delayed::Worker.destroy_failed_jobs = false
  477 + Delayed::Worker.max_attempts = 1
  478 + worker.run(@job)
  479 + @job.reload
  480 + expect(@job.last_error).to match(/did not work/)
  481 + expect(@job.attempts).to eq(1)
  482 + expect(@job).to be_failed
  483 + end
  484 +
  485 + it "re-schedules jobs after failing" do
  486 + worker.work_off
  487 + @job.reload
  488 + expect(@job.last_error).to match(/did not work/)
  489 + expect(@job.last_error).to match(/sample_jobs.rb:\d+:in `perform'/)
  490 + expect(@job.attempts).to eq(1)
  491 + expect(@job.run_at).to be > Delayed::Job.db_time_now - 10.minutes
  492 + expect(@job.run_at).to be < Delayed::Job.db_time_now + 10.minutes
  493 + expect(@job.locked_by).to be_nil
  494 + expect(@job.locked_at).to be_nil
  495 + end
  496 +
  497 + it "re-schedules jobs with handler provided time if present" do
  498 + job = Delayed::Job.enqueue(CustomRescheduleJob.new(99.minutes))
  499 + worker.run(job)
  500 + job.reload
  501 +
  502 + expect((Delayed::Job.db_time_now + 99.minutes - job.run_at).abs).to be < 1
  503 + end
  504 +
  505 + it "does not fail when the triggered error doesn't have a message" do
  506 + error_with_nil_message = StandardError.new
  507 + error_with_nil_message.stub(:message).and_return nil
  508 + @job.stub(:invoke_job).and_raise error_with_nil_message
  509 + expect{worker.run(@job)}.not_to raise_error
  510 + end
  511 + end
  512 +
  513 + context "reschedule" do
  514 + before do
  515 + @job = Delayed::Job.create :payload_object => SimpleJob.new
  516 + end
  517 +
  518 + share_examples_for "any failure more than Worker.max_attempts times" do
  519 + context "when the job's payload has a #failure hook" do
  520 + before do
  521 + @job = Delayed::Job.create :payload_object => OnPermanentFailureJob.new
  522 + expect(@job.payload_object).to respond_to :failure
  523 + end
  524 +
  525 + it "runs that hook" do
  526 + @job.payload_object.should_receive :failure
  527 + worker.reschedule(@job)
  528 + end
  529 + end
  530 +
  531 + context "when the job's payload has no #failure hook" do
  532 + # It's a little tricky to test this in a straightforward way,
  533 + # because putting a should_not_receive expectation on
  534 + # @job.payload_object.failure makes that object
  535 + # incorrectly return true to
  536 + # payload_object.respond_to? :failure, which is what
  537 + # reschedule uses to decide whether to call failure.
  538 + # So instead, we just make sure that the payload_object as it
  539 + # already stands doesn't respond_to? failure, then
  540 + # shove it through the iterated reschedule loop and make sure we
  541 + # don't get a NoMethodError (caused by calling that nonexistent
  542 + # failure method).
  543 +
  544 + before do
  545 + expect(@job.payload_object).not_to respond_to(:failure)
  546 + end
  547 +
  548 + it "does not try to run that hook" do
  549 + expect {
  550 + Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
  551 + }.not_to raise_exception
  552 + end
  553 + end
  554 + end
  555 +
  556 + context "and we want to destroy jobs" do
  557 + it_should_behave_like "any failure more than Worker.max_attempts times"
  558 +
  559 + it "is destroyed if it failed more than Worker.max_attempts times" do
  560 + @job.should_receive(:destroy)
  561 + Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
  562 + end
  563 +
  564 + it "is not destroyed if failed fewer than Worker.max_attempts times" do
  565 + @job.should_not_receive(:destroy)
  566 + (Delayed::Worker.max_attempts - 1).times { worker.reschedule(@job) }
  567 + end
  568 + end
  569 +
  570 + context "and we don't want to destroy jobs" do
  571 + before do
  572 + Delayed::Worker.destroy_failed_jobs = false
  573 + end
  574 +
  575 + after do
  576 + Delayed::Worker.destroy_failed_jobs = true
  577 + end
  578 +
  579 + it_should_behave_like "any failure more than Worker.max_attempts times"
  580 +
  581 + it "is failed if it failed more than Worker.max_attempts times" do
  582 + expect(@job.reload).not_to be_failed
  583 + Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
  584 + expect(@job.reload).to be_failed
  585 + end
  586 +
  587 + it "is not failed if it failed fewer than Worker.max_attempts times" do
  588 + (Delayed::Worker.max_attempts - 1).times { worker.reschedule(@job) }
  589 + expect(@job.reload).not_to be_failed
  590 + end
  591 + end
  592 + end
  593 + end
  594 +end
... ...
vendor/plugins/delayed_job/lib/delayed/command.rb
1   -require 'rubygems'
2   -require 'daemons'
  1 +begin
  2 + require 'daemons'
  3 +rescue LoadError
  4 + raise "You need to add gem 'daemons' to your Gemfile if you wish to use it."
  5 +end
3 6 require 'optparse'
4 7  
5 8 module Delayed
6 9 class Command
7 10 attr_accessor :worker_count
8   -
  11 +
9 12 def initialize(args)
10   - @files_to_reopen = []
11 13 @options = {
12 14 :quiet => true,
13 15 :pid_dir => "#{Rails.root}/tmp/pids"
14 16 }
15   -
  17 +
16 18 @worker_count = 1
17 19 @monitor = false
18   -
  20 +
19 21 opts = OptionParser.new do |opts|
20 22 opts.banner = "Usage: #{File.basename($0)} [options] start|stop|restart|run"
21 23  
... ... @@ -44,22 +46,32 @@ module Delayed
44 46 opts.on('-m', '--monitor', 'Start monitor process.') do
45 47 @monitor = true
46 48 end
47   -
48   -
  49 + opts.on('--sleep-delay N', "Amount of time to sleep when no jobs are found") do |n|
  50 + @options[:sleep_delay] = n.to_i
  51 + end
  52 + opts.on('--read-ahead N', "Number of jobs from the queue to consider") do |n|
  53 + @options[:read_ahead] = n
  54 + end
  55 + opts.on('-p', '--prefix NAME', "String to be prefixed to worker process names") do |prefix|
  56 + @options[:prefix] = prefix
  57 + end
  58 + opts.on('--queues=queues', "Specify which queue DJ must look up for jobs") do |queues|
  59 + @options[:queues] = queues.split(',')
  60 + end
  61 + opts.on('--queue=queue', "Specify which queue DJ must look up for jobs") do |queue|
  62 + @options[:queues] = queue.split(',')
  63 + end
  64 + opts.on('--exit-on-complete', "Exit when no more jobs are available to run. This will exit if all jobs are scheduled to run in the future.") do
  65 + @options[:exit_on_complete] = true
  66 + end
49 67 end
50 68 @args = opts.parse!(args)
51 69 end
52   -
53   - def daemonize
54   - Delayed::Worker.backend.before_fork
55 70  
56   - ObjectSpace.each_object(File) do |file|
57   - @files_to_reopen << file unless file.closed?
58   - end
59   -
  71 + def daemonize
60 72 dir = @options[:pid_dir]
61 73 Dir.mkdir(dir) unless File.exists?(dir)
62   -
  74 +
63 75 if @worker_count > 1 && @options[:identifier]
64 76 raise ArgumentError, 'Cannot specify both --number-of-workers and --identifier'
65 77 elsif @worker_count == 1 && @options[:identifier]
... ... @@ -72,28 +84,21 @@ module Delayed
72 84 end
73 85 end
74 86 end
75   -
  87 +
76 88 def run_process(process_name, dir)
  89 + Delayed::Worker.before_fork
77 90 Daemons.run_proc(process_name, :dir => dir, :dir_mode => :normal, :monitor => @monitor, :ARGV => @args) do |*args|
  91 + $0 = File.join(@options[:prefix], process_name) if @options[:prefix]
78 92 run process_name
79 93 end
80 94 end
81   -
  95 +
82 96 def run(worker_name = nil)
83 97 Dir.chdir(Rails.root)
84   -
85   - # Re-open file handles
86   - @files_to_reopen.each do |file|
87   - begin
88   - file.reopen file.path, "a+"
89   - file.sync = true
90   - rescue ::Exception
91   - end
92   - end
93   -
94   - Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
95   - Delayed::Worker.backend.after_fork
96   -
  98 +
  99 + Delayed::Worker.after_fork
  100 + Delayed::Worker.logger ||= Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
  101 +
97 102 worker = Delayed::Worker.new(@options)
98 103 worker.name_prefix = "#{worker_name} "
99 104 worker.start
... ... @@ -102,6 +107,5 @@ module Delayed
102 107 STDERR.puts e.message
103 108 exit 1
104 109 end
105   -
106 110 end
107 111 end
... ...
vendor/plugins/delayed_job/lib/delayed/compatibility.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +require 'active_support/version'
  2 +
  3 +module Delayed
  4 + module Compatibility
  5 + if ActiveSupport::VERSION::MAJOR >= 4
  6 + require 'active_support/proxy_object'
  7 +
  8 + def self.executable_prefix
  9 + 'bin'
  10 + end
  11 +
  12 + def self.proxy_object_class
  13 + ActiveSupport::ProxyObject
  14 + end
  15 + else
  16 + require 'active_support/basic_object'
  17 +
  18 + def self.executable_prefix
  19 + 'script'
  20 + end
  21 +
  22 + def self.proxy_object_class
  23 + ActiveSupport::BasicObject
  24 + end
  25 + end
  26 + end
  27 +end
... ...
vendor/plugins/delayed_job/lib/delayed/deserialization_error.rb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +module Delayed
  2 + class DeserializationError < StandardError
  3 + end
  4 +end
... ...
vendor/plugins/delayed_job/lib/delayed/exceptions.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +require 'timeout'
  2 +
  3 +module Delayed
  4 + class WorkerTimeout < Timeout::Error
  5 + def message
  6 + "#{super} (Delayed::Worker.max_run_time is only #{Delayed::Worker.max_run_time.to_i} seconds)"
  7 + end
  8 + end
  9 +end
... ...
vendor/plugins/delayed_job/lib/delayed/lifecycle.rb 0 → 100644
... ... @@ -0,0 +1,84 @@
  1 +module Delayed
  2 + class InvalidCallback < Exception; end
  3 +
  4 + class Lifecycle
  5 + EVENTS = {
  6 + :enqueue => [:job],
  7 + :execute => [:worker],
  8 + :loop => [:worker],
  9 + :perform => [:worker, :job],
  10 + :error => [:worker, :job],
  11 + :failure => [:worker, :job],
  12 + :invoke_job => [:job]
  13 + }
  14 +
  15 + def initialize
  16 + @callbacks = EVENTS.keys.inject({}) { |hash, e| hash[e] = Callback.new; hash }
  17 + end
  18 +
  19 + def before(event, &block)
  20 + add(:before, event, &block)
  21 + end
  22 +
  23 + def after(event, &block)
  24 + add(:after, event, &block)
  25 + end
  26 +
  27 + def around(event, &block)
  28 + add(:around, event, &block)
  29 + end
  30 +
  31 + def run_callbacks(event, *args, &block)
  32 + missing_callback(event) unless @callbacks.has_key?(event)
  33 +
  34 + unless EVENTS[event].size == args.size
  35 + raise ArgumentError, "Callback #{event} expects #{EVENTS[event].size} parameter(s): #{EVENTS[event].join(', ')}"
  36 + end
  37 +
  38 + @callbacks[event].execute(*args, &block)
  39 + end
  40 +
  41 + private
  42 +
  43 + def add(type, event, &block)
  44 + missing_callback(event) unless @callbacks.has_key?(event)
  45 +
  46 + @callbacks[event].add(type, &block)
  47 + end
  48 +
  49 + def missing_callback(event)
  50 + raise InvalidCallback, "Unknown callback event: #{event}"
  51 + end
  52 + end
  53 +
  54 + class Callback
  55 + def initialize
  56 + @before = []
  57 + @after = []
  58 +
  59 + # Identity proc. Avoids special cases when there is no existing around chain.
  60 + @around = lambda { |*args, &block| block.call(*args) }
  61 + end
  62 +
  63 + def execute(*args, &block)
  64 + @before.each { |c| c.call(*args) }
  65 + result = @around.call(*args, &block)
  66 + @after.each { |c| c.call(*args) }
  67 + result
  68 + end
  69 +
  70 + def add(type, &callback)
  71 + case type
  72 + when :before
  73 + @before << callback
  74 + when :after
  75 + @after << callback
  76 + when :around
  77 + chain = @around # use a local variable so that the current chain is closed over in the following lambda
  78 + @around = lambda { |*a, &block| chain.call(*a) { |*b| callback.call(*b, &block) } }
  79 + else
  80 + raise InvalidCallback, "Invalid callback type: #{type}"
  81 + end
  82 + end
  83 + end
  84 +end
... ...
vendor/plugins/delayed_job/lib/delayed/message_sending.rb
1   -require 'active_support/basic_object'
  1 +require 'active_support/core_ext/module/aliasing'
2 2  
3 3 module Delayed
4   - class DelayProxy < ActiveSupport::BasicObject
5   - def initialize(target, options)
  4 + class DelayProxy < Delayed::Compatibility.proxy_object_class
  5 + def initialize(payload_class, target, options)
  6 + @payload_class = payload_class
6 7 @target = target
7 8 @options = options
8 9 end
9 10  
10 11 def method_missing(method, *args)
11   - if (Rails.env == "test" or Rails.env == "cucumber" and !$DISABLE_DELAYED_JOB_TEST_ENV_RUN)
12   - @target.send method, *args
13   - return
14   - end
15   - Job.create({
16   - :payload_object => PerformableMethod.new(@target, method.to_sym, args),
17   - :priority => ::Delayed::Worker.default_priority
18   - }.merge(@options))
  12 + Job.enqueue({:payload_object => @payload_class.new(@target, method.to_sym, args)}.merge(@options))
19 13 end
20 14 end
21 15  
22 16 module MessageSending
23 17 def delay(options = {})
24   - DelayProxy.new(self, options)
  18 + DelayProxy.new(PerformableMethod, self, options)
25 19 end
26 20 alias __delay__ delay
27   -
  21 +
28 22 def send_later(method, *args)
29 23 warn "[DEPRECATION] `object.send_later(:method)` is deprecated. Use `object.delay.method"
30 24 __delay__.__send__(method, *args)
... ... @@ -34,17 +28,26 @@ module Delayed
34 28 warn "[DEPRECATION] `object.send_at(time, :method)` is deprecated. Use `object.delay(:run_at => time).method"
35 29 __delay__(:run_at => time).__send__(method, *args)
36 30 end
37   -
  31 +
38 32 module ClassMethods
39   - def handle_asynchronously(method)
40   - return if (Rails.env == "test" or Rails.env == "cucumber")
  33 + def handle_asynchronously(method, opts = {})
41 34 aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
42 35 with_method, without_method = "#{aliased_method}_with_delay#{punctuation}", "#{aliased_method}_without_delay#{punctuation}"
43 36 define_method(with_method) do |*args|
44   - delay.__send__(without_method, *args)
  37 + curr_opts = opts.clone
  38 + curr_opts.each_key do |key|
  39 + if (val = curr_opts[key]).is_a?(Proc)
  40 + curr_opts[key] = if val.arity == 1
  41 + val.call(self)
  42 + else
  43 + val.call
  44 + end
  45 + end
  46 + end
  47 + delay(curr_opts).__send__(without_method, *args)
45 48 end
46 49 alias_method_chain method, :delay
47 50 end
48 51 end
49   - end
  52 + end
50 53 end
... ...
vendor/plugins/delayed_job/lib/delayed/performable_mailer.rb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +require 'mail'
  2 +
  3 +module Delayed
  4 + class PerformableMailer < PerformableMethod
  5 + def perform
  6 + object.send(method_name, *args).deliver
  7 + end
  8 + end
  9 +
  10 + module DelayMail
  11 + def delay(options = {})
  12 + DelayProxy.new(PerformableMailer, self, options)
  13 + end
  14 + end
  15 +end
  16 +
  17 +Mail::Message.class_eval do
  18 + def delay(*args)
  19 + raise RuntimeError, "Use MyMailer.delay.mailer_action(args) to delay sending of emails."
  20 + end
  21 +end
... ...
vendor/plugins/delayed_job/lib/delayed/performable_method.rb
  1 +require 'active_support/core_ext/module/delegation'
  2 +
1 3 module Delayed
2   - class PerformableMethod < Struct.new(:object, :method, :args)
3   - def initialize(object, method, args)
4   - raise NoMethodError, "undefined method `#{method}' for #{object.inspect}" unless object.respond_to?(method, true)
  4 + class PerformableMethod
  5 + attr_accessor :object, :method_name, :args
  6 +
  7 + delegate :method, :to => :object
  8 +
  9 + def initialize(object, method_name, args)
  10 + raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)
5 11  
6   - self.object = object
7   - self.args = args
8   - self.method = method.to_sym
  12 + if object.respond_to?(:new_record?) && object.new_record?
  13 + raise(ArgumentError, 'Jobs cannot be created for records before they\'ve been persisted')
  14 + end
  15 +
  16 + self.object = object
  17 + self.args = args
  18 + self.method_name = method_name.to_sym
9 19 end
10   -
  20 +
11 21 def display_name
12   - "#{object.class}##{method}"
  22 + "#{object.class}##{method_name}"
13 23 end
14   -
  24 +
15 25 def perform
16   - object.send(method, *args) if object
  26 + object.send(method_name, *args) if object
17 27 end
18   -
  28 +
19 29 def method_missing(symbol, *args)
20   - object.respond_to?(symbol) ? object.send(symbol, *args) : super
  30 + object.send(symbol, *args)
21 31 end
22   -
  32 +
23 33 def respond_to?(symbol, include_private=false)
24   - object.respond_to?(symbol, include_private) || super
25   - end
  34 + super || object.respond_to?(symbol, include_private)
  35 + end
26 36 end
27 37 end
... ...
vendor/plugins/delayed_job/lib/delayed/plugin.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +require 'active_support/core_ext/class/attribute'
  2 +
  3 +module Delayed
  4 + class Plugin
  5 + class_attribute :callback_block
  6 +
  7 + def self.callbacks(&block)
  8 + self.callback_block = block
  9 + end
  10 +
  11 + def initialize
  12 + self.class.callback_block.call(Delayed::Worker.lifecycle) if self.class.callback_block
  13 + end
  14 + end
  15 +end
... ...
vendor/plugins/delayed_job/lib/delayed/plugins/clear_locks.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +module Delayed
  2 + module Plugins
  3 + class ClearLocks < Plugin
  4 + callbacks do |lifecycle|
  5 + lifecycle.around(:execute) do |worker, &block|
  6 + begin
  7 + block.call(worker)
  8 + ensure
  9 + Delayed::Job.clear_locks!(worker.name)
  10 + end
  11 + end
  12 + end
  13 + end
  14 + end
  15 +end
... ...
vendor/plugins/delayed_job/lib/delayed/psych_ext.rb 0 → 100644
... ... @@ -0,0 +1,146 @@
  1 +if defined?(ActiveRecord)
  2 + ActiveRecord::Base.class_eval do
  3 + if instance_methods.include?(:encode_with)
  4 + def encode_with_override(coder)
  5 + encode_with_without_override(coder)
  6 + coder.tag = "!ruby/ActiveRecord:#{self.class.name}"
  7 + end
  8 + alias_method :encode_with_without_override, :encode_with
  9 + alias_method :encode_with, :encode_with_override
  10 + else
  11 + def encode_with(coder)
  12 + coder["attributes"] = attributes
  13 + coder.tag = "!ruby/ActiveRecord:#{self.class.name}"
  14 + end
  15 + end
  16 + end
  17 +end
  18 +
  19 +class Delayed::PerformableMethod
  20 + # serialize to YAML
  21 + def encode_with(coder)
  22 + coder.map = {
  23 + "object" => object,
  24 + "method_name" => method_name,
  25 + "args" => args
  26 + }
  27 + end
  28 +end
  29 +
  30 +module Psych
  31 + module Visitors
  32 + class YAMLTree
  33 + def visit_Class(klass)
  34 + @emitter.scalar klass.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED
  35 + end
  36 + end
  37 +
  38 + class ToRuby
  39 + def visit_Psych_Nodes_Scalar(o)
  40 + @st[o.anchor] = o.value if o.anchor
  41 +
  42 + if klass = Psych.load_tags[o.tag]
  43 + instance = klass.allocate
  44 +
  45 + if instance.respond_to?(:init_with)
  46 + coder = Psych::Coder.new(o.tag)
  47 + coder.scalar = o.value
  48 + instance.init_with coder
  49 + end
  50 +
  51 + return instance
  52 + end
  53 +
  54 + return o.value if o.quoted
  55 + return @ss.tokenize(o.value) unless o.tag
  56 +
  57 + case o.tag
  58 + when '!binary', 'tag:yaml.org,2002:binary'
  59 + o.value.unpack('m').first
  60 + when '!str', 'tag:yaml.org,2002:str'
  61 + o.value
  62 + when "!ruby/object:DateTime"
  63 + require 'date'
  64 + @ss.parse_time(o.value).to_datetime
  65 + when "!ruby/object:Complex"
  66 + Complex(o.value)
  67 + when "!ruby/object:Rational"
  68 + Rational(o.value)
  69 + when "!ruby/class", "!ruby/module"
  70 + resolve_class o.value
  71 + when "tag:yaml.org,2002:float", "!float"
  72 + Float(@ss.tokenize(o.value))
  73 + when "!ruby/regexp"
  74 + o.value =~ /^\/(.*)\/([mixn]*)$/
  75 + source = $1
  76 + options = 0
  77 + lang = nil
  78 + ($2 || '').split('').each do |option|
  79 + case option
  80 + when 'x' then options |= Regexp::EXTENDED
  81 + when 'i' then options |= Regexp::IGNORECASE
  82 + when 'm' then options |= Regexp::MULTILINE
  83 + when 'n' then options |= Regexp::NOENCODING
  84 + else lang = option
  85 + end
  86 + end
  87 + Regexp.new(*[source, options, lang].compact)
  88 + when "!ruby/range"
  89 + args = o.value.split(/([.]{2,3})/, 2).map { |s|
  90 + accept Nodes::Scalar.new(s)
  91 + }
  92 + args.push(args.delete_at(1) == '...')
  93 + Range.new(*args)
  94 + when /^!ruby\/sym(bol)?:?(.*)?$/
  95 + o.value.to_sym
  96 + else
  97 + @ss.tokenize o.value
  98 + end
  99 + end
  100 +
  101 + def visit_Psych_Nodes_Mapping_with_class(object)
  102 + return revive(Psych.load_tags[object.tag], object) if Psych.load_tags[object.tag]
  103 +
  104 + case object.tag
  105 + when /^!ruby\/ActiveRecord:(.+)$/
  106 + klass = resolve_class($1)
  107 + payload = Hash[*object.children.map { |c| accept c }]
  108 + id = payload["attributes"][klass.primary_key]
  109 + begin
  110 + klass.unscoped.find(id)
  111 + rescue ActiveRecord::RecordNotFound
  112 + raise Delayed::DeserializationError
  113 + end
  114 + when /^!ruby\/Mongoid:(.+)$/
  115 + klass = resolve_class($1)
  116 + payload = Hash[*object.children.map { |c| accept c }]
  117 + begin
  118 + klass.find(payload["attributes"]["_id"])
  119 + rescue Mongoid::Errors::DocumentNotFound
  120 + raise Delayed::DeserializationError
  121 + end
  122 + when /^!ruby\/DataMapper:(.+)$/
  123 + klass = resolve_class($1)
  124 + payload = Hash[*object.children.map { |c| accept c }]
  125 + begin
  126 + primary_keys = klass.properties.select { |p| p.key? }
  127 + key_names = primary_keys.map { |p| p.name.to_s }
  128 + klass.get!(*key_names.map { |k| payload["attributes"][k] })
  129 + rescue DataMapper::ObjectNotFoundError
  130 + raise Delayed::DeserializationError
  131 + end
  132 + else
  133 + visit_Psych_Nodes_Mapping_without_class(object)
  134 + end
  135 + end
  136 + alias_method_chain :visit_Psych_Nodes_Mapping, :class
  137 +
  138 + def resolve_class_with_constantize(klass_name)
  139 + klass_name.constantize
  140 + rescue
  141 + resolve_class_without_constantize(klass_name)
  142 + end
  143 + alias_method_chain :resolve_class, :constantize
  144 + end
  145 + end
  146 +end
... ...
vendor/plugins/delayed_job/lib/delayed/railtie.rb
... ... @@ -4,7 +4,9 @@ require &#39;rails&#39;
4 4 module Delayed
5 5 class Railtie < Rails::Railtie
6 6 initializer :after_initialize do
7   - Delayed::Worker.guess_backend
  7 + ActiveSupport.on_load(:action_mailer) do
  8 + ActionMailer::Base.send(:extend, Delayed::DelayMail)
  9 + end
8 10 end
9 11  
10 12 rake_tasks do
... ...
vendor/plugins/delayed_job/lib/delayed/recipes.rb
... ... @@ -6,26 +6,49 @@
6 6 # after "deploy:stop", "delayed_job:stop"
7 7 # after "deploy:start", "delayed_job:start"
8 8 # after "deploy:restart", "delayed_job:restart"
  9 +#
  10 +# If you want to use command line options, for example to start multiple workers,
  11 +# define a Capistrano variable delayed_job_args:
  12 +#
  13 +# set :delayed_job_args, "-n 2"
  14 +#
  15 +# If you've got delayed_job workers running on a servers, you can also specify
  16 +# which servers have delayed_job running and should be restarted after deploy.
  17 +#
  18 +# set :delayed_job_server_role, :worker
  19 +#
9 20  
10 21 Capistrano::Configuration.instance.load do
11 22 namespace :delayed_job do
12 23 def rails_env
13 24 fetch(:rails_env, false) ? "RAILS_ENV=#{fetch(:rails_env)}" : ''
14 25 end
15   -
  26 +
  27 + def args
  28 + fetch(:delayed_job_args, "")
  29 + end
  30 +
  31 + def roles
  32 + fetch(:delayed_job_server_role, :app)
  33 + end
  34 +
  35 + def delayed_job_command
  36 + fetch(:delayed_job_command, "script/delayed_job")
  37 + end
  38 +
16 39 desc "Stop the delayed_job process"
17   - task :stop, :roles => :app do
18   - run "cd #{current_path};#{rails_env} script/delayed_job stop"
  40 + task :stop, :roles => lambda { roles } do
  41 + run "cd #{current_path};#{rails_env} #{delayed_job_command} stop"
19 42 end
20 43  
21 44 desc "Start the delayed_job process"
22   - task :start, :roles => :app do
23   - run "cd #{current_path};#{rails_env} script/delayed_job start"
  45 + task :start, :roles => lambda { roles } do
  46 + run "cd #{current_path};#{rails_env} #{delayed_job_command} start #{args}"
24 47 end
25 48  
26 49 desc "Restart the delayed_job process"
27   - task :restart, :roles => :app do
28   - run "cd #{current_path};#{rails_env} script/delayed_job restart"
  50 + task :restart, :roles => lambda { roles } do
  51 + run "cd #{current_path};#{rails_env} #{delayed_job_command} restart #{args}"
29 52 end
30 53 end
31   -end
32 54 \ No newline at end of file
  55 +end
... ...
vendor/plugins/delayed_job/lib/delayed/serialization/active_record.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +if defined?(ActiveRecord)
  2 + class ActiveRecord::Base
  3 + yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
  4 +
  5 + def self.yaml_new(klass, tag, val)
  6 + klass.unscoped.find(val['attributes'][klass.primary_key])
  7 + rescue ActiveRecord::RecordNotFound
  8 + raise Delayed::DeserializationError, "ActiveRecord::RecordNotFound, class: #{klass} , primary key: #{val['attributes'][klass.primary_key]} "
  9 + end
  10 +
  11 + def to_yaml_properties
  12 + ['@attributes']
  13 + end
  14 + end
  15 +end
... ...
vendor/plugins/delayed_job/lib/delayed/syck_ext.rb 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +class Module
  2 + yaml_as "tag:ruby.yaml.org,2002:module"
  3 +
  4 + def self.yaml_new(klass, tag, val)
  5 + val.constantize
  6 + end
  7 +
  8 + def to_yaml(options = {})
  9 + YAML.quick_emit(nil, options) do |out|
  10 + out.scalar(taguri, name, :plain)
  11 + end
  12 + end
  13 +
  14 + def yaml_tag_read_class(name)
  15 + # Constantize the object so that ActiveSupport can attempt
  16 + # its auto loading magic. Will raise LoadError if not successful.
  17 + name.constantize
  18 + name
  19 + end
  20 +end
  21 +
  22 +class Class
  23 + yaml_as "tag:ruby.yaml.org,2002:class"
  24 + remove_method :to_yaml if respond_to?(:to_yaml) && method(:to_yaml).owner == Class # use Module's to_yaml
  25 +end
  26 +
  27 +class Struct
  28 + def self.yaml_tag_read_class(name)
  29 + # Constantize the object so that ActiveSupport can attempt
  30 + # its auto loading magic. Will raise LoadError if not successful.
  31 + name.constantize
  32 + "Struct::#{ name }"
  33 + end
  34 +end
... ...
vendor/plugins/delayed_job/lib/delayed/tasks.rb
1   -# Re-definitions are appended to existing tasks
2   -task :environment
3   -task :merb_env
4   -
5 1 namespace :jobs do
6 2 desc "Clear the delayed_job queue."
7   - task :clear => [:merb_env, :environment] do
  3 + task :clear => :environment do
8 4 Delayed::Job.delete_all
9 5 end
10 6  
11 7 desc "Start a delayed_job worker."
12   - task :work => [:merb_env, :environment] do
13   - Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY']).start
  8 + task :work => :environment_options do
  9 + Delayed::Worker.new(@worker_options).start
  10 + end
  11 +
  12 + desc "Start a delayed_job worker and exit when all available jobs are complete."
  13 + task :workoff => :environment_options do
  14 + Delayed::Worker.new(@worker_options.merge({:exit_on_complete => true})).start
14 15 end
  16 +
  17 + task :environment_options => :environment do
  18 + @worker_options = {
  19 + :min_priority => ENV['MIN_PRIORITY'],
  20 + :max_priority => ENV['MAX_PRIORITY'],
  21 + :queues => (ENV['QUEUES'] || ENV['QUEUE'] || '').split(','),
  22 + :quiet => false
  23 + }
  24 + end
  25 +
  26 + desc "Exit with error status if any jobs older than max_age seconds haven't been attempted yet."
  27 + task :check, [:max_age] => :environment do |_, args|
  28 + args.with_defaults(:max_age => 300)
  29 +
  30 + unprocessed_jobs = Delayed::Job.where('attempts = 0 AND created_at < ?', Time.now - args[:max_age].to_i).count
  31 +
  32 + if unprocessed_jobs > 0
  33 + fail "#{unprocessed_jobs} jobs older than #{args[:max_age]} seconds have not been processed yet"
  34 + end
  35 +
  36 + end
  37 +
15 38 end
... ...
vendor/plugins/delayed_job/lib/delayed/worker.rb
... ... @@ -2,59 +2,122 @@ require &#39;timeout&#39;
2 2 require 'active_support/core_ext/numeric/time'
3 3 require 'active_support/core_ext/class/attribute_accessors'
4 4 require 'active_support/core_ext/kernel'
  5 +require 'active_support/core_ext/enumerable'
  6 +require 'logger'
  7 +require 'benchmark'
5 8  
6 9 module Delayed
7 10 class Worker
8   - cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time, :default_priority, :sleep_delay, :logger
9   - self.sleep_delay = 5
10   - self.max_attempts = 25
11   - self.max_run_time = 4.hours
12   - self.default_priority = 0
13   -
  11 + DEFAULT_LOG_LEVEL = Logger::INFO
  12 + DEFAULT_SLEEP_DELAY = 5
  13 + DEFAULT_MAX_ATTEMPTS = 25
  14 + DEFAULT_MAX_RUN_TIME = 4.hours
  15 + DEFAULT_DEFAULT_PRIORITY = 0
  16 + DEFAULT_DELAY_JOBS = true
  17 + DEFAULT_QUEUES = []
  18 + DEFAULT_READ_AHEAD = 5
  19 +
  20 + cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time,
  21 + :default_priority, :sleep_delay, :logger, :delay_jobs, :queues,
  22 + :read_ahead, :plugins, :destroy_failed_jobs, :exit_on_complete
  23 +
  24 + # Named queue into which jobs are enqueued by default
  25 + cattr_accessor :default_queue_name
  26 +
  27 + cattr_reader :backend
  28 +
  29 + # name_prefix is ignored if name is set directly
  30 + attr_accessor :name_prefix
  31 +
  32 + def self.reset
  33 + self.sleep_delay = DEFAULT_SLEEP_DELAY
  34 + self.max_attempts = DEFAULT_MAX_ATTEMPTS
  35 + self.max_run_time = DEFAULT_MAX_RUN_TIME
  36 + self.default_priority = DEFAULT_DEFAULT_PRIORITY
  37 + self.delay_jobs = DEFAULT_DELAY_JOBS
  38 + self.queues = DEFAULT_QUEUES
  39 + self.read_ahead = DEFAULT_READ_AHEAD
  40 + end
  41 +
  42 + reset
  43 +
  44 + # Add or remove plugins in this list before the worker is instantiated
  45 + self.plugins = [Delayed::Plugins::ClearLocks]
  46 +
14 47 # By default failed jobs are destroyed after too many attempts. If you want to keep them around
15 48 # (perhaps to inspect the reason for the failure), set this to false.
16   - cattr_accessor :destroy_failed_jobs
17 49 self.destroy_failed_jobs = true
18   -
19   - self.logger = if defined?(Merb::Logger)
20   - Merb.logger
  50 +
  51 + # By default, Signals INT and TERM set @exit, and the worker exits upon completion of the current job.
  52 + # If you would prefer to raise a SignalException and exit immediately you can use this.
  53 + # Be aware daemons uses TERM to stop and restart
  54 + # false - No exceptions will be raised
  55 + # :term - Will only raise an exception on TERM signals but INT will wait for the current job to finish
  56 + # true - Will raise an exception on TERM and INT
  57 + cattr_accessor :raise_signal_exceptions
  58 + self.raise_signal_exceptions = false
  59 +
  60 + self.logger = if defined?(Rails)
  61 + Rails.logger
21 62 elsif defined?(RAILS_DEFAULT_LOGGER)
22 63 RAILS_DEFAULT_LOGGER
23 64 end
24 65  
25   - # name_prefix is ignored if name is set directly
26   - attr_accessor :name_prefix
27   -
28   - cattr_reader :backend
29   -
30 66 def self.backend=(backend)
31 67 if backend.is_a? Symbol
  68 + require "delayed/serialization/#{backend}"
32 69 require "delayed/backend/#{backend}"
33 70 backend = "Delayed::Backend::#{backend.to_s.classify}::Job".constantize
34 71 end
35 72 @@backend = backend
36 73 silence_warnings { ::Delayed.const_set(:Job, backend) }
37 74 end
38   -
  75 +
39 76 def self.guess_backend
40   - self.backend ||= if defined?(ActiveRecord)
41   - :active_record
42   - elsif defined?(MongoMapper)
43   - :mongo_mapper
44   - else
45   - logger.warn "Could not decide on a backend, defaulting to active_record"
46   - :active_record
  77 + warn "[DEPRECATION] guess_backend is deprecated. Please remove it from your code."
  78 + end
  79 +
  80 + def self.before_fork
  81 + unless @files_to_reopen
  82 + @files_to_reopen = []
  83 + ObjectSpace.each_object(File) do |file|
  84 + @files_to_reopen << file unless file.closed?
  85 + end
47 86 end
  87 +
  88 + backend.before_fork
  89 + end
  90 +
  91 + def self.after_fork
  92 + # Re-open file handles
  93 + @files_to_reopen.each do |file|
  94 + begin
  95 + file.reopen file.path, "a+"
  96 + file.sync = true
  97 + rescue ::Exception
  98 + end
  99 + end
  100 +
  101 + backend.after_fork
  102 + end
  103 +
  104 + def self.lifecycle
  105 + @lifecycle ||= Delayed::Lifecycle.new
48 106 end
49 107  
50 108 def initialize(options={})
51   - @quiet = options[:quiet]
52   - self.class.min_priority = options[:min_priority] if options.has_key?(:min_priority)
53   - self.class.max_priority = options[:max_priority] if options.has_key?(:max_priority)
  109 + @quiet = options.has_key?(:quiet) ? options[:quiet] : true
  110 + @failed_reserve_count = 0
  111 +
  112 + [:min_priority, :max_priority, :sleep_delay, :read_ahead, :queues, :exit_on_complete].each do |option|
  113 + self.class.send("#{option}=", options[option]) if options.has_key?(option)
  114 + end
  115 +
  116 + self.plugins.each { |klass| klass.new }
54 117 end
55 118  
56 119 # Every worker has a unique name which by default is the pid of the process. There are some
57   - # advantages to overriding this with something which survives worker retarts: Workers can#
  120 + # advantages to overriding this with something which survives worker restarts: Workers can
58 121 # safely resume working on tasks which are locked by themselves. The worker will assume that
59 122 # it crashed before.
60 123 def name
... ... @@ -69,35 +132,54 @@ module Delayed
69 132 end
70 133  
71 134 def start
72   - say "Starting job worker"
  135 + trap('TERM') do
  136 + say 'Exiting...'
  137 + stop
  138 + raise SignalException.new('TERM') if self.class.raise_signal_exceptions
  139 + end
73 140  
74   - trap('TERM') { say 'Exiting...'; $exit = true }
75   - trap('INT') { say 'Exiting...'; $exit = true }
  141 + trap('INT') do
  142 + say 'Exiting...'
  143 + stop
  144 + raise SignalException.new('INT') if self.class.raise_signal_exceptions && self.class.raise_signal_exceptions != :term
  145 + end
76 146  
77   - loop do
78   - result = nil
  147 + say "Starting job worker"
79 148  
80   - realtime = Benchmark.realtime do
81   - result = work_off
82   - end
  149 + self.class.lifecycle.run_callbacks(:execute, self) do
  150 + loop do
  151 + self.class.lifecycle.run_callbacks(:loop, self) do
  152 + @realtime = Benchmark.realtime do
  153 + @result = work_off
  154 + end
  155 + end
83 156  
84   - count = result.sum
  157 + count = @result.sum
85 158  
86   - break if $exit
  159 + if count.zero?
  160 + if self.class.exit_on_complete
  161 + say "No more jobs available. Exiting"
  162 + break
  163 + else
  164 + sleep(self.class.sleep_delay) unless stop?
  165 + end
  166 + else
  167 + say "#{count} jobs processed at %.4f j/s, %d failed" % [count / @realtime, @result.last]
  168 + end
87 169  
88   - if count.zero?
89   - sleep(@@sleep_delay)
90   - else
91   - say "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / realtime, result.last]
  170 + break if stop?
92 171 end
93   -
94   - break if $exit
95 172 end
  173 + end
  174 +
  175 + def stop
  176 + @exit = true
  177 + end
96 178  
97   - ensure
98   - Delayed::Job.clear_locks!(name)
  179 + def stop?
  180 + !!@exit
99 181 end
100   -
  182 +
101 183 # Do num jobs and return stats on success/failure.
102 184 # Exit early if interrupted.
103 185 def work_off(num = 100)
... ... @@ -112,80 +194,90 @@ module Delayed
112 194 else
113 195 break # leave if no work could be done
114 196 end
115   - break if $exit # leave if we're exiting
  197 + break if stop? # leave if we're exiting
116 198 end
117 199  
118 200 return [success, failure]
119 201 end
120   -
  202 +
121 203 def run(job)
  204 + job_say job, 'RUNNING'
122 205 runtime = Benchmark.realtime do
123   - Timeout.timeout(self.class.max_run_time.to_i) { job.invoke_job }
  206 + Timeout.timeout(self.class.max_run_time.to_i, WorkerTimeout) { job.invoke_job }
124 207 job.destroy
125 208 end
126   - say "#{job.name} completed after %.4f" % runtime
  209 + job_say job, 'COMPLETED after %.4f' % runtime
127 210 return true # did work
128   - rescue Exception => e
129   - handle_failed_job(job, e)
  211 + rescue DeserializationError => error
  212 + job.last_error = "#{error.message}\n#{error.backtrace.join("\n")}"
  213 + failed(job)
  214 + rescue Exception => error
  215 + self.class.lifecycle.run_callbacks(:error, self, job){ handle_failed_job(job, error) }
130 216 return false # work failed
131 217 end
132   -
  218 +
133 219 # Reschedule the job in the future (when a job fails).
134 220 # Uses an exponential scale depending on the number of failed attempts.
135 221 def reschedule(job, time = nil)
136   - if (job.attempts += 1) < self.class.max_attempts
137   - time ||= Job.db_time_now + (job.attempts ** 4) + 5
  222 + if (job.attempts += 1) < max_attempts(job)
  223 + time ||= job.reschedule_at
138 224 job.run_at = time
139 225 job.unlock
140 226 job.save!
141 227 else
142   - say "PERMANENTLY removing #{job.name} because of #{job.attempts} consecutive failures.", Logger::INFO
143   -
144   - if job.payload_object.respond_to? :on_permanent_failure
145   - say "Running on_permanent_failure hook"
146   - failure_method = job.payload_object.method(:on_permanent_failure)
147   - if failure_method.arity == 1
148   - failure_method.call(job)
149   - else
150   - failure_method.call
151   - end
152   - end
  228 + job_say job, "REMOVED permanently because of #{job.attempts} consecutive failures", Logger::ERROR
  229 + failed(job)
  230 + end
  231 + end
153 232  
154   - self.class.destroy_failed_jobs ? job.destroy : job.update_attributes(:failed_at => Delayed::Job.db_time_now)
  233 + def failed(job)
  234 + self.class.lifecycle.run_callbacks(:failure, self, job) do
  235 + job.hook(:failure)
  236 + self.class.destroy_failed_jobs ? job.destroy : job.fail!
155 237 end
156 238 end
157 239  
158   - def say(text, level = Logger::INFO)
  240 + def job_say(job, text, level = DEFAULT_LOG_LEVEL)
  241 + text = "Job #{job.name} (id=#{job.id}) #{text}"
  242 + say text, level
  243 + end
  244 +
  245 + def say(text, level = DEFAULT_LOG_LEVEL)
159 246 text = "[Worker(#{name})] #{text}"
160 247 puts text unless @quiet
161 248 logger.add level, "#{Time.now.strftime('%FT%T%z')}: #{text}" if logger
162 249 end
163 250  
  251 + def max_attempts(job)
  252 + job.max_attempts || self.class.max_attempts
  253 + end
  254 +
164 255 protected
165   -
  256 +
166 257 def handle_failed_job(job, error)
167   - job.last_error = error.message + "\n" + error.backtrace.join("\n")
168   - say "#{job.name} failed with #{error.class.name}: #{error.message} - #{job.attempts} failed attempts", Logger::ERROR
  258 + job.last_error = "#{error.message}\n#{error.backtrace.join("\n")}"
  259 + job_say job, "FAILED (#{job.attempts} prior attempts) with #{error.class.name}: #{error.message}", Logger::ERROR
169 260 reschedule(job)
170 261 end
171   -
  262 +
172 263 # Run the next job we can get an exclusive lock on.
173 264 # If no jobs are left we return nil
174 265 def reserve_and_run_one_job
  266 + job = reserve_job
  267 + self.class.lifecycle.run_callbacks(:perform, self, job){ run(job) } if job
  268 + end
175 269  
176   - # We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next.
177   - # this leads to a more even distribution of jobs across the worker processes
178   - job = Delayed::Job.find_available(name, 5, self.class.max_run_time).detect do |job|
179   - if job.lock_exclusively!(self.class.max_run_time, name)
180   - say "acquired lock on #{job.name}"
181   - true
182   - else
183   - say "failed to acquire exclusive lock for #{job.name}", Logger::WARN
184   - false
185   - end
186   - end
187   -
188   - run(job) if job
  270 + def reserve_job
  271 + job = Delayed::Job.reserve(self)
  272 + @failed_reserve_count = 0
  273 + job
  274 + rescue Exception => error
  275 + say "Error while reserving job: #{error}"
  276 + Delayed::Job.recover_from(error)
  277 + @failed_reserve_count += 1
  278 + raise FatalBackendError if @failed_reserve_count >= 10
  279 + nil
189 280 end
190 281 end
  282 +
191 283 end
... ...
vendor/plugins/delayed_job/lib/delayed/yaml_ext.rb
... ... @@ -2,34 +2,9 @@
2 2 # Classes, Modules and Structs
3 3  
4 4 require 'yaml'
5   -
6   -class Module
7   - yaml_as "tag:ruby.yaml.org,2002:module"
8   -
9   - def self.yaml_new(klass, tag, val)
10   - val.constantize
11   - end
12   -
13   - def to_yaml( opts = {} )
14   - YAML::quick_emit( nil, opts ) { |out|
15   - out.scalar(taguri, self.name, :plain)
16   - }
17   - end
18   -
19   - def yaml_tag_read_class(name)
20   - # Constantize the object so that ActiveSupport can attempt
21   - # its auto loading magic. Will raise LoadError if not successful.
22   - name.constantize
23   - name
24   - end
25   -
26   -end
27   -
28   -class Struct
29   - def self.yaml_tag_read_class(name)
30   - # Constantize the object so that ActiveSupport can attempt
31   - # its auto loading magic. Will raise LoadError if not successful.
32   - name.constantize
33   - "Struct::#{ name }"
34   - end
  5 +if YAML.parser.class.name =~ /syck|yecht/i
  6 + require File.expand_path('../syck_ext', __FILE__)
  7 + require File.expand_path('../serialization/active_record', __FILE__)
  8 +else
  9 + require File.expand_path('../psych_ext', __FILE__)
35 10 end
... ...
vendor/plugins/delayed_job/lib/delayed_job.rb
1 1 require 'active_support'
  2 +require 'delayed/compatibility'
  3 +require 'delayed/exceptions'
  4 +require 'delayed/message_sending'
  5 +require 'delayed/performable_method'
2 6  
3   -require File.dirname(__FILE__) + '/delayed/message_sending'
4   -require File.dirname(__FILE__) + '/delayed/performable_method'
5   -require File.dirname(__FILE__) + '/delayed/yaml_ext'
6   -require File.dirname(__FILE__) + '/delayed/backend/base'
7   -require File.dirname(__FILE__) + '/delayed/worker'
8   -require File.dirname(__FILE__) + '/delayed/railtie' if defined?(::Rails::Railtie)
  7 +if defined?(ActionMailer)
  8 + require 'action_mailer/version'
  9 + require 'delayed/performable_mailer'
  10 +end
9 11  
10   -Object.send(:include, Delayed::MessageSending)
11   -Module.send(:include, Delayed::MessageSending::ClassMethods)
  12 +require 'delayed/yaml_ext'
  13 +require 'delayed/lifecycle'
  14 +require 'delayed/plugin'
  15 +require 'delayed/plugins/clear_locks'
  16 +require 'delayed/backend/base'
  17 +require 'delayed/worker'
  18 +require 'delayed/deserialization_error'
  19 +require 'delayed/railtie' if defined?(Rails::Railtie)
12 20  
13   -if defined?(Merb::Plugins)
14   - Merb::Plugins.add_rakefiles File.dirname(__FILE__) / 'delayed' / 'tasks'
15   -end
  21 +Object.send(:include, Delayed::MessageSending)
  22 +Module.send(:include, Delayed::MessageSending::ClassMethods)
... ...
vendor/plugins/delayed_job/lib/generators/delayed_job/delayed_job_generator.rb
1 1 require 'rails/generators'
2   -require 'rails/generators/migration'
  2 +require 'delayed/compatibility'
3 3  
4 4 class DelayedJobGenerator < Rails::Generators::Base
5 5  
6   - include Rails::Generators::Migration
7   -
8   - def self.source_root
9   - @source_root ||= File.join(File.dirname(__FILE__), 'templates')
10   - end
  6 + self.source_paths << File.join(File.dirname(__FILE__), 'templates')
11 7  
12   - # Implement the required interface for Rails::Generators::Migration.
13   - #
14   - def self.next_migration_number(dirname) #:nodoc:
15   - next_migration_number = current_migration_number(dirname) + 1
16   - if ActiveRecord::Base.timestamped_migrations
17   - [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
18   - else
19   - "%.3d" % next_migration_number
20   - end
21   - end
22   -
23   - def create_script_file
24   - template 'script', 'script/delayed_job'
25   - chmod 'script/delayed_job', 0755
  8 + def create_executable_file
  9 + template "script", "#{Delayed::Compatibility.executable_prefix}/delayed_job"
  10 + chmod "#{Delayed::Compatibility.executable_prefix}/delayed_job", 0755
26 11 end
27   -
28   - def create_migration_file
29   - if defined?(ActiveRecord)
30   - migration_template 'migration.rb', 'db/migrate/create_delayed_jobs.rb'
31   - end
32   - end
33   -
34   -end
35 12 \ No newline at end of file
  13 +end
... ...
vendor/plugins/delayed_job/lib/generators/delayed_job/templates/migration.rb
... ... @@ -1,21 +0,0 @@
1   -class CreateDelayedJobs < ActiveRecord::Migration
2   - def self.up
3   - create_table :delayed_jobs, :force => true do |table|
4   - table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
5   - table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
6   - table.text :handler # YAML-encoded string of the object that will do work
7   - table.text :last_error # reason for last failure (See Note below)
8   - table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9   - table.datetime :locked_at # Set when a client is working on this object
10   - table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11   - table.string :locked_by # Who is working on this object (if locked)
12   - table.timestamps
13   - end
14   -
15   - add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16   - end
17   -
18   - def self.down
19   - drop_table :delayed_jobs
20   - end
21   -end
22 0 \ No newline at end of file
vendor/plugins/delayed_job/lib/generators/delayed_job/templates/script 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +#!/usr/bin/env ruby
  2 +
  3 +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
  4 +require 'delayed/command'
  5 +Delayed::Command.new(ARGV).daemonize
... ...
vendor/plugins/delayed_job/rails/init.rb
... ... @@ -1 +0,0 @@
1   -require 'delayed_job'
vendor/plugins/delayed_job/spec/autoloaded/clazz.rb
... ... @@ -4,4 +4,4 @@ module Autoloaded
4 4 def perform
5 5 end
6 6 end
7   -end
8 7 \ No newline at end of file
  8 +end
... ...
vendor/plugins/delayed_job/spec/autoloaded/instance_clazz.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +module Autoloaded
  2 + class InstanceClazz
  3 + def perform
  4 + end
  5 + end
  6 +end
... ...
vendor/plugins/delayed_job/spec/autoloaded/instance_struct.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +module Autoloaded
  2 + class InstanceStruct < ::Struct.new(nil)
  3 + def perform
  4 + end
  5 + end
  6 +end
... ...
vendor/plugins/delayed_job/spec/autoloaded/struct.rb
... ... @@ -4,4 +4,4 @@ module Autoloaded
4 4 def perform
5 5 end
6 6 end
7   -end
8 7 \ No newline at end of file
  8 +end
... ...
vendor/plugins/delayed_job/spec/backend/active_record_job_spec.rb
... ... @@ -1,46 +0,0 @@
1   -require 'spec_helper'
2   -require 'backend/shared_backend_spec'
3   -require 'delayed/backend/active_record'
4   -
5   -describe Delayed::Backend::ActiveRecord::Job do
6   - before(:all) do
7   - @backend = Delayed::Backend::ActiveRecord::Job
8   - end
9   -
10   - before(:each) do
11   - Delayed::Backend::ActiveRecord::Job.delete_all
12   - SimpleJob.runs = 0
13   - end
14   -
15   - after do
16   - Time.zone = nil
17   - end
18   -
19   - it_should_behave_like 'a backend'
20   -
21   - context "db_time_now" do
22   - it "should return time in current time zone if set" do
23   - Time.zone = 'Eastern Time (US & Canada)'
24   - %w(EST EDT).should include(Delayed::Job.db_time_now.zone)
25   - end
26   -
27   - it "should return UTC time if that is the AR default" do
28   - Time.zone = nil
29   - ActiveRecord::Base.default_timezone = :utc
30   - Delayed::Backend::ActiveRecord::Job.db_time_now.zone.should == 'UTC'
31   - end
32   -
33   - it "should return local time if that is the AR default" do
34   - Time.zone = 'Central Time (US & Canada)'
35   - ActiveRecord::Base.default_timezone = :local
36   - %w(CST CDT).should include(Delayed::Backend::ActiveRecord::Job.db_time_now.zone)
37   - end
38   - end
39   -
40   - describe "after_fork" do
41   - it "should call reconnect on the connection" do
42   - ActiveRecord::Base.connection.should_receive(:reconnect!)
43   - Delayed::Backend::ActiveRecord::Job.after_fork
44   - end
45   - end
46   -end
vendor/plugins/delayed_job/spec/backend/couch_rest_job_spec.rb
... ... @@ -1,15 +0,0 @@
1   -require 'spec_helper'
2   -require 'backend/shared_backend_spec'
3   -require 'delayed/backend/couch_rest'
4   -
5   -describe Delayed::Backend::CouchRest::Job do
6   - before(:all) do
7   - @backend = Delayed::Backend::CouchRest::Job
8   - end
9   -
10   - before(:each) do
11   - @backend.delete_all
12   - end
13   -
14   - it_should_behave_like 'a backend'
15   -end
vendor/plugins/delayed_job/spec/backend/data_mapper_job_spec.rb
... ... @@ -1,16 +0,0 @@
1   -require 'spec_helper'
2   -require 'backend/shared_backend_spec'
3   -require 'delayed/backend/data_mapper'
4   -
5   -describe Delayed::Backend::DataMapper::Job do
6   - before(:all) do
7   - @backend = Delayed::Backend::DataMapper::Job
8   - end
9   -
10   - before(:each) do
11   - # reset database before each example is run
12   - DataMapper.auto_migrate!
13   - end
14   -
15   - it_should_behave_like 'a backend'
16   -end
vendor/plugins/delayed_job/spec/backend/mongo_mapper_job_spec.rb
... ... @@ -1,94 +0,0 @@
1   -require 'spec_helper'
2   -require 'backend/shared_backend_spec'
3   -require 'delayed/backend/mongo_mapper'
4   -
5   -describe Delayed::Backend::MongoMapper::Job do
6   - before(:all) do
7   - @backend = Delayed::Backend::MongoMapper::Job
8   - end
9   -
10   - before(:each) do
11   - MongoMapper.database.collections.each(&:remove)
12   - end
13   -
14   - it_should_behave_like 'a backend'
15   -
16   - describe "indexes" do
17   - it "should have combo index on priority and run_at" do
18   - @backend.collection.index_information.detect { |index| index[0] == 'priority_1_run_at_1' }.should_not be_nil
19   - end
20   -
21   - it "should have index on locked_by" do
22   - @backend.collection.index_information.detect { |index| index[0] == 'locked_by_1' }.should_not be_nil
23   - end
24   - end
25   -
26   - describe "delayed method" do
27   - class MongoStoryReader
28   - def read(story)
29   - "Epilog: #{story.tell}"
30   - end
31   - end
32   -
33   - class MongoStory
34   - include ::MongoMapper::Document
35   - key :text, String
36   -
37   - def tell
38   - text
39   - end
40   - end
41   -
42   - it "should ignore not found errors because they are permanent" do
43   - story = MongoStory.create :text => 'Once upon a time...'
44   - job = story.delay.tell
45   - story.destroy
46   - lambda { job.invoke_job }.should_not raise_error
47   - end
48   -
49   - it "should store the object as string" do
50   - story = MongoStory.create :text => 'Once upon a time...'
51   - job = story.delay.tell
52   -
53   - job.payload_object.class.should == Delayed::PerformableMethod
54   - job.payload_object.object.should == story
55   - job.payload_object.method.should == :tell
56   - job.payload_object.args.should == []
57   - job.payload_object.perform.should == 'Once upon a time...'
58   - end
59   -
60   - it "should store arguments as string" do
61   - story = MongoStory.create :text => 'Once upon a time...'
62   - job = MongoStoryReader.new.delay.read(story)
63   - job.payload_object.class.should == Delayed::PerformableMethod
64   - job.payload_object.method.should == :read
65   - job.payload_object.args.should == [story]
66   - job.payload_object.perform.should == 'Epilog: Once upon a time...'
67   - end
68   - end
69   -
70   - describe "before_fork" do
71   - after do
72   - MongoMapper.connection.connect_to_master
73   - end
74   -
75   - it "should disconnect" do
76   - lambda do
77   - Delayed::Backend::MongoMapper::Job.before_fork
78   - end.should change { !!MongoMapper.connection.connected? }.from(true).to(false)
79   - end
80   - end
81   -
82   - describe "after_fork" do
83   - before do
84   - MongoMapper.connection.close
85   - end
86   -
87   - it "should call reconnect" do
88   - lambda do
89   - Delayed::Backend::MongoMapper::Job.after_fork
90   - end.should change { !!MongoMapper.connection.connected? }.from(false).to(true)
91   - end
92   - end
93   -
94   -end
vendor/plugins/delayed_job/spec/backend/shared_backend_spec.rb
... ... @@ -1,279 +0,0 @@
1   -class NamedJob < Struct.new(:perform)
2   - def display_name
3   - 'named_job'
4   - end
5   -end
6   -
7   -shared_examples_for 'a backend' do
8   - def create_job(opts = {})
9   - @backend.create(opts.merge(:payload_object => SimpleJob.new))
10   - end
11   -
12   - before do
13   - Delayed::Worker.max_priority = nil
14   - Delayed::Worker.min_priority = nil
15   - Delayed::Worker.default_priority = 99
16   - SimpleJob.runs = 0
17   - end
18   -
19   - it "should set run_at automatically if not set" do
20   - @backend.create(:payload_object => ErrorJob.new ).run_at.should_not be_nil
21   - end
22   -
23   - it "should not set run_at automatically if already set" do
24   - later = @backend.db_time_now + 5.minutes
25   - @backend.create(:payload_object => ErrorJob.new, :run_at => later).run_at.should be_close(later, 1)
26   - end
27   -
28   - it "should raise ArgumentError when handler doesn't respond_to :perform" do
29   - lambda { @backend.enqueue(Object.new) }.should raise_error(ArgumentError)
30   - end
31   -
32   - it "should increase count after enqueuing items" do
33   - @backend.enqueue SimpleJob.new
34   - @backend.count.should == 1
35   - end
36   -
37   - it "should be able to set priority when enqueuing items" do
38   - @job = @backend.enqueue SimpleJob.new, 5
39   - @job.priority.should == 5
40   - end
41   -
42   - it "should use default priority when it is not set" do
43   - @job = @backend.enqueue SimpleJob.new
44   - @job.priority.should == 99
45   - end
46   -
47   - it "should be able to set run_at when enqueuing items" do
48   - later = @backend.db_time_now + 5.minutes
49   - @job = @backend.enqueue SimpleJob.new, 5, later
50   - @job.run_at.should be_close(later, 1)
51   - end
52   -
53   - it "should work with jobs in modules" do
54   - M::ModuleJob.runs = 0
55   - job = @backend.enqueue M::ModuleJob.new
56   - lambda { job.invoke_job }.should change { M::ModuleJob.runs }.from(0).to(1)
57   - end
58   -
59   - describe "payload_object" do
60   - it "should raise a DeserializationError when the job class is totally unknown" do
61   - job = @backend.new :handler => "--- !ruby/object:JobThatDoesNotExist {}"
62   - lambda { job.payload_object }.should raise_error(Delayed::Backend::DeserializationError)
63   - end
64   -
65   - it "should raise a DeserializationError when the job struct is totally unknown" do
66   - job = @backend.new :handler => "--- !ruby/struct:StructThatDoesNotExist {}"
67   - lambda { job.payload_object }.should raise_error(Delayed::Backend::DeserializationError)
68   - end
69   -
70   - it "should autoload classes that are unknown at runtime" do
71   - job = @backend.new :handler => "--- !ruby/object:Autoloaded::Clazz {}"
72   - lambda { job.payload_object }.should_not raise_error(Delayed::Backend::DeserializationError)
73   - end
74   -
75   - it "should autoload structs that are unknown at runtime" do
76   - job = @backend.new :handler => "--- !ruby/struct:Autoloaded::Struct {}"
77   - lambda { job.payload_object }.should_not raise_error(Delayed::Backend::DeserializationError)
78   - end
79   - end
80   -
81   - describe "find_available" do
82   - it "should not find failed jobs" do
83   - @job = create_job :attempts => 50, :failed_at => @backend.db_time_now
84   - @backend.find_available('worker', 5, 1.second).should_not include(@job)
85   - end
86   -
87   - it "should not find jobs scheduled for the future" do
88   - @job = create_job :run_at => (@backend.db_time_now + 1.minute)
89   - @backend.find_available('worker', 5, 4.hours).should_not include(@job)
90   - end
91   -
92   - it "should not find jobs locked by another worker" do
93   - @job = create_job(:locked_by => 'other_worker', :locked_at => @backend.db_time_now - 1.minute)
94   - @backend.find_available('worker', 5, 4.hours).should_not include(@job)
95   - end
96   -
97   - it "should find open jobs" do
98   - @job = create_job
99   - @backend.find_available('worker', 5, 4.hours).should include(@job)
100   - end
101   -
102   - it "should find expired jobs" do
103   - @job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now - 2.minutes)
104   - @backend.find_available('worker', 5, 1.minute).should include(@job)
105   - end
106   -
107   - it "should find own jobs" do
108   - @job = create_job(:locked_by => 'worker', :locked_at => (@backend.db_time_now - 1.minutes))
109   - @backend.find_available('worker', 5, 4.hours).should include(@job)
110   - end
111   -
112   - it "should find only the right amount of jobs" do
113   - 10.times { create_job }
114   - @backend.find_available('worker', 7, 4.hours).should have(7).jobs
115   - end
116   - end
117   -
118   - context "when another worker is already performing an task, it" do
119   -
120   - before :each do
121   - @job = @backend.create :payload_object => SimpleJob.new, :locked_by => 'worker1', :locked_at => @backend.db_time_now - 5.minutes
122   - end
123   -
124   - it "should not allow a second worker to get exclusive access" do
125   - @job.lock_exclusively!(4.hours, 'worker2').should == false
126   - end
127   -
128   - it "should allow a second worker to get exclusive access if the timeout has passed" do
129   - @job.lock_exclusively!(1.minute, 'worker2').should == true
130   - end
131   -
132   - it "should be able to get access to the task if it was started more then max_age ago" do
133   - @job.locked_at = 5.hours.ago
134   - @job.save
135   -
136   - @job.lock_exclusively! 4.hours, 'worker2'
137   - @job.reload
138   - @job.locked_by.should == 'worker2'
139   - @job.locked_at.should > 1.minute.ago
140   - end
141   -
142   - it "should not be found by another worker" do
143   - @backend.find_available('worker2', 1, 6.minutes).length.should == 0
144   - end
145   -
146   - it "should be found by another worker if the time has expired" do
147   - @backend.find_available('worker2', 1, 4.minutes).length.should == 1
148   - end
149   -
150   - it "should be able to get exclusive access again when the worker name is the same" do
151   - @job.lock_exclusively!(5.minutes, 'worker1').should be_true
152   - @job.lock_exclusively!(5.minutes, 'worker1').should be_true
153   - @job.lock_exclusively!(5.minutes, 'worker1').should be_true
154   - end
155   - end
156   -
157   - context "when another worker has worked on a task since the job was found to be available, it" do
158   -
159   - before :each do
160   - @job = @backend.create :payload_object => SimpleJob.new
161   - @job_copy_for_worker_2 = @backend.find(@job.id)
162   - end
163   -
164   - it "should not allow a second worker to get exclusive access if already successfully processed by worker1" do
165   - @job.destroy
166   - @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
167   - end
168   -
169   - it "should not allow a second worker to get exclusive access if failed to be processed by worker1 and run_at time is now in future (due to backing off behaviour)" do
170   - @job.update_attributes(:attempts => 1, :run_at => 1.day.from_now)
171   - @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
172   - end
173   - end
174   -
175   - context "#name" do
176   - it "should be the class name of the job that was enqueued" do
177   - @backend.create(:payload_object => ErrorJob.new ).name.should == 'ErrorJob'
178   - end
179   -
180   - it "should be the method that will be called if its a performable method object" do
181   - job = @backend.new(:payload_object => NamedJob.new)
182   - job.name.should == 'named_job'
183   - end
184   -
185   - it "should be the instance method that will be called if its a performable method object" do
186   - @job = Story.create(:text => "...").delay.save
187   - @job.name.should == 'Story#save'
188   - end
189   - end
190   -
191   - context "worker prioritization" do
192   - before(:each) do
193   - Delayed::Worker.max_priority = nil
194   - Delayed::Worker.min_priority = nil
195   - end
196   -
197   - it "should fetch jobs ordered by priority" do
198   - 10.times { @backend.enqueue SimpleJob.new, rand(10) }
199   - jobs = @backend.find_available('worker', 10)
200   - jobs.size.should == 10
201   - jobs.each_cons(2) do |a, b|
202   - a.priority.should <= b.priority
203   - end
204   - end
205   -
206   - it "should only find jobs greater than or equal to min priority" do
207   - min = 5
208   - Delayed::Worker.min_priority = min
209   - 10.times {|i| @backend.enqueue SimpleJob.new, i }
210   - jobs = @backend.find_available('worker', 10)
211   - jobs.each {|job| job.priority.should >= min}
212   - end
213   -
214   - it "should only find jobs less than or equal to max priority" do
215   - max = 5
216   - Delayed::Worker.max_priority = max
217   - 10.times {|i| @backend.enqueue SimpleJob.new, i }
218   - jobs = @backend.find_available('worker', 10)
219   - jobs.each {|job| job.priority.should <= max}
220   - end
221   - end
222   -
223   - context "clear_locks!" do
224   - before do
225   - @job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now)
226   - end
227   -
228   - it "should clear locks for the given worker" do
229   - @backend.clear_locks!('worker')
230   - @backend.find_available('worker2', 5, 1.minute).should include(@job)
231   - end
232   -
233   - it "should not clear locks for other workers" do
234   - @backend.clear_locks!('worker1')
235   - @backend.find_available('worker1', 5, 1.minute).should_not include(@job)
236   - end
237   - end
238   -
239   - context "unlock" do
240   - before do
241   - @job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now)
242   - end
243   -
244   - it "should clear locks" do
245   - @job.unlock
246   - @job.locked_by.should be_nil
247   - @job.locked_at.should be_nil
248   - end
249   - end
250   -
251   - context "large handler" do
252   - before do
253   - text = "Lorem ipsum dolor sit amet. " * 1000
254   - @job = @backend.enqueue Delayed::PerformableMethod.new(text, :length, {})
255   - end
256   -
257   - it "should have an id" do
258   - @job.id.should_not be_nil
259   - end
260   - end
261   -
262   - describe "yaml serialization" do
263   - it "should reload changed attributes" do
264   - job = @backend.enqueue SimpleJob.new
265   - yaml = job.to_yaml
266   - job.priority = 99
267   - job.save
268   - YAML.load(yaml).priority.should == 99
269   - end
270   -
271   - it "should ignore destroyed records" do
272   - job = @backend.enqueue SimpleJob.new
273   - yaml = job.to_yaml
274   - job.destroy
275   - lambda { YAML.load(yaml).should be_nil }.should_not raise_error
276   - end
277   - end
278   -
279   -end
vendor/plugins/delayed_job/spec/delayed/backend/test.rb 0 → 100644
... ... @@ -0,0 +1,112 @@
  1 +require 'ostruct'
  2 +
  3 +# An in-memory backend suitable only for testing. Tries to behave as if it were an ORM.
  4 +module Delayed
  5 + module Backend
  6 + module Test
  7 + class Job
  8 + attr_accessor :id
  9 + attr_accessor :priority
  10 + attr_accessor :attempts
  11 + attr_accessor :handler
  12 + attr_accessor :last_error
  13 + attr_accessor :run_at
  14 + attr_accessor :locked_at
  15 + attr_accessor :locked_by
  16 + attr_accessor :failed_at
  17 + attr_accessor :queue
  18 +
  19 + include Delayed::Backend::Base
  20 +
  21 + cattr_accessor :id
  22 + self.id = 0
  23 +
  24 + def initialize(hash = {})
  25 + self.attempts = 0
  26 + self.priority = 0
  27 + self.id = (self.class.id += 1)
  28 + hash.each{|k,v| send(:"#{k}=", v)}
  29 + end
  30 +
  31 + @jobs = []
  32 + def self.all
  33 + @jobs
  34 + end
  35 +
  36 + def self.count
  37 + all.size
  38 + end
  39 +
  40 + def self.delete_all
  41 + all.clear
  42 + end
  43 +
  44 + def self.create(attrs = {})
  45 + new(attrs).tap do |o|
  46 + o.save
  47 + end
  48 + end
  49 +
  50 + def self.create!(*args); create(*args); end
  51 +
  52 + def self.clear_locks!(worker_name)
  53 + all.select{|j| j.locked_by == worker_name}.each {|j| j.locked_by = nil; j.locked_at = nil}
  54 + end
  55 +
  56 + # Find a few candidate jobs to run (in case some immediately get locked by others).
  57 + def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
  58 + jobs = all.select do |j|
  59 + j.run_at <= db_time_now &&
  60 + (j.locked_at.nil? || j.locked_at < db_time_now - max_run_time || j.locked_by == worker_name) &&
  61 + !j.failed?
  62 + end
  63 +
  64 + jobs = jobs.select{|j| Worker.queues.include?(j.queue)} if Worker.queues.any?
  65 + jobs = jobs.select{|j| j.priority >= Worker.min_priority} if Worker.min_priority
  66 + jobs = jobs.select{|j| j.priority <= Worker.max_priority} if Worker.max_priority
  67 + jobs.sort_by{|j| [j.priority, j.run_at]}[0..limit-1]
  68 + end
  69 +
  70 + # Lock this job for this worker.
  71 + # Returns true if we have the lock, false otherwise.
  72 + def lock_exclusively!(max_run_time, worker)
  73 + now = self.class.db_time_now
  74 + if locked_by != worker
  75 + # We don't own this job so we will update the locked_by name and the locked_at
  76 + self.locked_at = now
  77 + self.locked_by = worker
  78 + end
  79 +
  80 + return true
  81 + end
  82 +
  83 + def self.db_time_now
  84 + Time.current
  85 + end
  86 +
  87 + def update_attributes(attrs = {})
  88 + attrs.each{|k,v| send(:"#{k}=", v)}
  89 + save
  90 + end
  91 +
  92 + def destroy
  93 + self.class.all.delete(self)
  94 + end
  95 +
  96 + def save
  97 + self.run_at ||= Time.current
  98 +
  99 + self.class.all << self unless self.class.all.include?(self)
  100 + true
  101 + end
  102 +
  103 + def save!; save; end
  104 +
  105 + def reload
  106 + reset
  107 + self
  108 + end
  109 + end
  110 + end
  111 + end
  112 +end
... ...
vendor/plugins/delayed_job/spec/delayed/serialization/test.rb 0 → 100644
vendor/plugins/delayed_job/spec/helper.rb 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +require 'logger'
  2 +require 'rspec'
  3 +
  4 +require 'action_mailer'
  5 +require 'active_support/dependencies'
  6 +require 'active_record'
  7 +
  8 +require 'delayed_job'
  9 +require 'delayed/backend/shared_spec'
  10 +
  11 +require 'simplecov'
  12 +require 'coveralls'
  13 +
  14 +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
  15 + SimpleCov::Formatter::HTMLFormatter,
  16 + Coveralls::SimpleCov::Formatter
  17 +]
  18 +SimpleCov.start
  19 +
  20 +Delayed::Worker.logger = Logger.new('/tmp/dj.log')
  21 +ENV['RAILS_ENV'] = 'test'
  22 +
  23 +Delayed::Worker.backend = :test
  24 +
  25 +# Add this directory so the ActiveSupport autoloading works
  26 +ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)
  27 +
  28 +# Add this to simulate Railtie initializer being executed
  29 +ActionMailer::Base.send(:extend, Delayed::DelayMail)
  30 +
  31 +
  32 +# Used to test interactions between DJ and an ORM
  33 +ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
  34 +ActiveRecord::Base.logger = Delayed::Worker.logger
  35 +ActiveRecord::Migration.verbose = false
  36 +
  37 +ActiveRecord::Schema.define do
  38 + create_table :stories, :primary_key => :story_id, :force => true do |table|
  39 + table.string :text
  40 + table.boolean :scoped, :default => true
  41 + end
  42 +end
  43 +
  44 +class Story < ActiveRecord::Base
  45 + self.primary_key = 'story_id'
  46 + def tell; text; end
  47 + def whatever(n, _); tell*n; end
  48 + default_scope { where(:scoped => true) }
  49 +
  50 + handle_asynchronously :whatever
  51 +end
  52 +
  53 +RSpec.configure do |config|
  54 + config.after(:each) do
  55 + Delayed::Worker.reset
  56 + end
  57 +
  58 + config.expect_with :rspec do |c|
  59 + c.syntax = :expect
  60 + end
  61 +end
... ...
vendor/plugins/delayed_job/spec/lifecycle_spec.rb 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +require 'helper'
  2 +
  3 +describe Delayed::Lifecycle do
  4 + let(:lifecycle) { Delayed::Lifecycle.new }
  5 + let(:callback) { lambda {|*args|} }
  6 + let(:arguments) { [1] }
  7 + let(:behavior) { double(Object, :before! => nil, :after! => nil, :inside! => nil) }
  8 + let(:wrapped_block) { Proc.new { behavior.inside! } }
  9 +
  10 + describe "before callbacks" do
  11 + before(:each) do
  12 + lifecycle.before(:execute, &callback)
  13 + end
  14 +
  15 + it "executes before wrapped block" do
  16 + callback.should_receive(:call).with(*arguments).ordered
  17 + behavior.should_receive(:inside!).ordered
  18 + lifecycle.run_callbacks :execute, *arguments, &wrapped_block
  19 + end
  20 + end
  21 +
  22 + describe "after callbacks" do
  23 + before(:each) do
  24 + lifecycle.after(:execute, &callback)
  25 + end
  26 +
  27 + it "executes after wrapped block" do
  28 + behavior.should_receive(:inside!).ordered
  29 + callback.should_receive(:call).with(*arguments).ordered
  30 + lifecycle.run_callbacks :execute, *arguments, &wrapped_block
  31 + end
  32 + end
  33 +
  34 + describe "around callbacks" do
  35 + before(:each) do
  36 + lifecycle.around(:execute) do |*args, &block|
  37 + behavior.before!
  38 + block.call(*args)
  39 + behavior.after!
  40 + end
  41 + end
  42 +
  43 + it "wraps a block" do
  44 + behavior.should_receive(:before!).ordered
  45 + behavior.should_receive(:inside!).ordered
  46 + behavior.should_receive(:after!).ordered
  47 + lifecycle.run_callbacks :execute, *arguments, &wrapped_block
  48 + end
  49 +
  50 + it "executes multiple callbacks in order" do
  51 + behavior.should_receive(:one).ordered
  52 + behavior.should_receive(:two).ordered
  53 + behavior.should_receive(:three).ordered
  54 +
  55 + lifecycle.around(:execute) { |*args, &block| behavior.one; block.call(*args) }
  56 + lifecycle.around(:execute) { |*args, &block| behavior.two; block.call(*args) }
  57 + lifecycle.around(:execute) { |*args, &block| behavior.three; block.call(*args) }
  58 +
  59 + lifecycle.run_callbacks(:execute, *arguments, &wrapped_block)
  60 + end
  61 + end
  62 +
  63 + it "raises if callback is executed with wrong number of parameters" do
  64 + lifecycle.before(:execute, &callback)
  65 + expect { lifecycle.run_callbacks(:execute, 1,2,3) {} }.to raise_error(ArgumentError, /1 parameter/)
  66 + end
  67 +end
... ...
vendor/plugins/delayed_job/spec/message_sending_spec.rb
1   -require 'spec_helper'
  1 +require 'helper'
2 2  
3 3 describe Delayed::MessageSending do
4 4 describe "handle_asynchronously" do
5   - class Story < ActiveRecord::Base
6   - def tell!(arg)
7   - end
  5 + class Story
  6 + def tell!(arg);end
8 7 handle_asynchronously :tell!
9 8 end
10   -
11   - it "should alias original method" do
12   - Story.new.should respond_to(:tell_without_delay!)
13   - Story.new.should respond_to(:tell_with_delay!)
  9 +
  10 + it "aliases original method" do
  11 + expect(Story.new).to respond_to(:tell_without_delay!)
  12 + expect(Story.new).to respond_to(:tell_with_delay!)
14 13 end
15   -
16   - it "should create a PerformableMethod" do
17   - story = Story.create!
18   - lambda {
  14 +
  15 + it "creates a PerformableMethod" do
  16 + story = Story.create
  17 + expect {
19 18 job = story.tell!(1)
20   - job.payload_object.class.should == Delayed::PerformableMethod
21   - job.payload_object.method.should == :tell_without_delay!
22   - job.payload_object.args.should == [1]
23   - }.should change { Delayed::Job.count }
  19 + expect(job.payload_object.class).to eq(Delayed::PerformableMethod)
  20 + expect(job.payload_object.method_name).to eq(:tell_without_delay!)
  21 + expect(job.payload_object.args).to eq([1])
  22 + }.to change { Delayed::Job.count }
  23 + end
  24 +
  25 + describe "with options" do
  26 + class Fable
  27 + cattr_accessor :importance
  28 + def tell;end
  29 + handle_asynchronously :tell, :priority => Proc.new { self.importance }
  30 + end
  31 +
  32 + it "sets the priority based on the Fable importance" do
  33 + Fable.importance = 10
  34 + job = Fable.new.tell
  35 + expect(job.priority).to eq(10)
  36 +
  37 + Fable.importance = 20
  38 + job = Fable.new.tell
  39 + expect(job.priority).to eq(20)
  40 + end
  41 +
  42 + describe "using a proc with parameters" do
  43 + class Yarn
  44 + attr_accessor :importance
  45 + def spin
  46 + end
  47 + handle_asynchronously :spin, :priority => Proc.new {|y| y.importance }
  48 + end
  49 +
  50 + it "sets the priority based on the Fable importance" do
  51 + job = Yarn.new.tap {|y| y.importance = 10 }.spin
  52 + expect(job.priority).to eq(10)
  53 +
  54 + job = Yarn.new.tap {|y| y.importance = 20 }.spin
  55 + expect(job.priority).to eq(20)
  56 + end
  57 + end
24 58 end
25 59 end
26 60  
27 61 context "delay" do
28   - it "should create a new PerformableMethod job" do
29   - lambda {
  62 + class FairyTail
  63 + attr_accessor :happy_ending
  64 + def self.princesses;end
  65 + def tell
  66 + @happy_ending = true
  67 + end
  68 + end
  69 +
  70 + after do
  71 + Delayed::Worker.default_queue_name = nil
  72 + end
  73 +
  74 + it "creates a new PerformableMethod job" do
  75 + expect {
30 76 job = "hello".delay.count('l')
31   - job.payload_object.class.should == Delayed::PerformableMethod
32   - job.payload_object.method.should == :count
33   - job.payload_object.args.should == ['l']
34   - }.should change { Delayed::Job.count }.by(1)
  77 + expect(job.payload_object.class).to eq(Delayed::PerformableMethod)
  78 + expect(job.payload_object.method_name).to eq(:count)
  79 + expect(job.payload_object.args).to eq(['l'])
  80 + }.to change { Delayed::Job.count }.by(1)
35 81 end
36 82  
37   - it "should set default priority" do
  83 + it "sets default priority" do
38 84 Delayed::Worker.default_priority = 99
39   - job = Object.delay.to_s
40   - job.priority.should == 99
41   - Delayed::Worker.default_priority = 0
  85 + job = FairyTail.delay.to_s
  86 + expect(job.priority).to eq(99)
42 87 end
43 88  
44   - it "should set job options" do
  89 + it "sets default queue name" do
  90 + Delayed::Worker.default_queue_name = 'abbazabba'
  91 + job = FairyTail.delay.to_s
  92 + expect(job.queue).to eq('abbazabba')
  93 + end
  94 +
  95 + it "sets job options" do
45 96 run_at = Time.parse('2010-05-03 12:55 AM')
46   - job = Object.delay(:priority => 20, :run_at => run_at).to_s
47   - job.run_at.should == run_at
48   - job.priority.should == 20
  97 + job = FairyTail.delay(:priority => 20, :run_at => run_at).to_s
  98 + expect(job.run_at).to eq(run_at)
  99 + expect(job.priority).to eq(20)
  100 + end
  101 +
  102 + it "does not delay the job when delay_jobs is false" do
  103 + Delayed::Worker.delay_jobs = false
  104 + fairy_tail = FairyTail.new
  105 + expect {
  106 + expect {
  107 + fairy_tail.delay.tell
  108 + }.to change(fairy_tail, :happy_ending).from(nil).to(true)
  109 + }.not_to change { Delayed::Job.count }
  110 + end
  111 +
  112 + it "does delay the job when delay_jobs is true" do
  113 + Delayed::Worker.delay_jobs = true
  114 + fairy_tail = FairyTail.new
  115 + expect {
  116 + expect {
  117 + fairy_tail.delay.tell
  118 + }.not_to change(fairy_tail, :happy_ending)
  119 + }.to change { Delayed::Job.count }.by(1)
49 120 end
50 121 end
51 122 end
... ...
vendor/plugins/delayed_job/spec/performable_mailer_spec.rb 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +require 'helper'
  2 +
  3 +require 'action_mailer'
  4 +class MyMailer < ActionMailer::Base
  5 + def signup(email)
  6 + mail :to => email, :subject => "Delaying Emails", :from => "delayedjob@example.com",:body => 'Delaying Emails Body'
  7 + end
  8 +end
  9 +
  10 +describe ActionMailer::Base do
  11 + describe "delay" do
  12 + it "enqueues a PerformableEmail job" do
  13 + expect {
  14 + job = MyMailer.delay.signup('john@example.com')
  15 + expect(job.payload_object.class).to eq(Delayed::PerformableMailer)
  16 + expect(job.payload_object.method_name).to eq(:signup)
  17 + expect(job.payload_object.args).to eq(['john@example.com'])
  18 + }.to change { Delayed::Job.count }.by(1)
  19 + end
  20 + end
  21 +
  22 + describe "delay on a mail object" do
  23 + it "raises an exception" do
  24 + expect {
  25 + MyMailer.signup('john@example.com').delay
  26 + }.to raise_error(RuntimeError)
  27 + end
  28 + end
  29 +
  30 + describe Delayed::PerformableMailer do
  31 + describe "perform" do
  32 + it "calls the method and #deliver on the mailer" do
  33 + email = double('email', :deliver => true)
  34 + mailer_class = double('MailerClass', :signup => email)
  35 + mailer = Delayed::PerformableMailer.new(mailer_class, :signup, ['john@example.com'])
  36 +
  37 + mailer_class.should_receive(:signup).with('john@example.com')
  38 + email.should_receive(:deliver)
  39 + mailer.perform
  40 + end
  41 + end
  42 + end
  43 +
  44 +end
... ...
vendor/plugins/delayed_job/spec/performable_method_spec.rb
1   -require 'spec_helper'
  1 +require 'helper'
2 2  
3 3 describe Delayed::PerformableMethod do
4 4 describe "perform" do
5 5 before do
6 6 @method = Delayed::PerformableMethod.new("foo", :count, ['o'])
7 7 end
8   -
  8 +
9 9 context "with the persisted record cannot be found" do
10 10 before do
11 11 @method.object = nil
12 12 end
13   -
14   - it "should be a no-op if object is nil" do
15   - lambda { @method.perform }.should_not raise_error
  13 +
  14 + it "does nothing if object is nil" do
  15 + expect{@method.perform}.not_to raise_error
16 16 end
17 17 end
18   -
19   - it "should call the method on the object" do
  18 +
  19 + it "calls the method on the object" do
20 20 @method.object.should_receive(:count).with('o')
21 21 @method.perform
22 22 end
23   -
24   - it "should respond to on_permanent_failure when implemented and target object is called via object.delay.do_something" do
25   - @method = Delayed::PerformableMethod.new(OnPermanentFailureJob.new, :perform, [])
26   - @method.respond_to?(:on_permanent_failure).should be_true
27   - @method.object.should_receive(:on_permanent_failure)
28   - @method.on_permanent_failure
29   - end
30 23 end
31 24  
32   - it "should raise a NoMethodError if target method doesn't exist" do
33   - lambda {
  25 + it "raises a NoMethodError if target method doesn't exist" do
  26 + expect {
34 27 Delayed::PerformableMethod.new(Object, :method_that_does_not_exist, [])
35   - }.should raise_error(NoMethodError)
  28 + }.to raise_error(NoMethodError)
36 29 end
37   -
38   - it "should not raise NoMethodError if target method is private" do
  30 +
  31 + it "does not raise NoMethodError if target method is private" do
39 32 clazz = Class.new do
40 33 def private_method
41 34 end
42 35 private :private_method
43 36 end
44   - lambda {
  37 + expect {
45 38 Delayed::PerformableMethod.new(clazz.new, :private_method, [])
46   - }.should_not raise_error(NoMethodError)
  39 + }.not_to raise_error
  40 + end
  41 +
  42 + describe "hooks" do
  43 + %w(before after success).each do |hook|
  44 + it "delegates #{hook} hook to object" do
  45 + story = Story.create
  46 + job = story.delay.tell
  47 +
  48 + story.should_receive(hook).with(job)
  49 + job.invoke_job
  50 + end
  51 + end
  52 +
  53 + %w(before after success).each do |hook|
  54 + it "delegates #{hook} hook to object" do
  55 + story = Story.create
  56 + job = story.delay.tell
  57 +
  58 + story.should_receive(hook).with(job)
  59 + job.invoke_job
  60 + end
  61 + end
  62 +
  63 + it "delegates enqueue hook to object" do
  64 + story = Story.create
  65 + story.should_receive(:enqueue).with(an_instance_of(Delayed::Job))
  66 + story.delay.tell
  67 + end
  68 +
  69 + it "delegates error hook to object" do
  70 + story = Story.create
  71 + story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
  72 + story.should_receive(:tell).and_raise(RuntimeError)
  73 + expect { story.delay.tell.invoke_job }.to raise_error
  74 + end
  75 +
  76 + it "delegates error hook to object when delay_jobs = false" do
  77 + story = Story.create
  78 + story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
  79 + story.should_receive(:tell).and_raise(RuntimeError)
  80 + expect { story.delay.tell.invoke_job }.to raise_error
  81 + end
  82 +
  83 + it "delegates failure hook to object" do
  84 + method = Delayed::PerformableMethod.new("object", :size, [])
  85 + method.object.should_receive(:failure)
  86 + method.failure
  87 + end
  88 +
  89 + context 'with delay_job == false' do
  90 + before do
  91 + Delayed::Worker.delay_jobs = false
  92 + end
  93 +
  94 + after do
  95 + Delayed::Worker.delay_jobs = true
  96 + end
  97 +
  98 + %w(before after success).each do |hook|
  99 + it "delegates #{hook} hook to object" do
  100 + story = Story.create
  101 + story.should_receive(hook).with(an_instance_of(Delayed::Job))
  102 + story.delay.tell
  103 + end
  104 + end
  105 +
  106 + %w(before after success).each do |hook|
  107 + it "delegates #{hook} hook to object" do
  108 + story = Story.create
  109 + story.should_receive(hook).with(an_instance_of(Delayed::Job))
  110 + story.delay.tell
  111 + end
  112 + end
  113 +
  114 + it "delegates error hook to object" do
  115 + story = Story.create
  116 + story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
  117 + story.should_receive(:tell).and_raise(RuntimeError)
  118 + expect { story.delay.tell }.to raise_error
  119 + end
  120 +
  121 + it "delegates error hook to object when delay_jobs = false" do
  122 + story = Story.create
  123 + story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
  124 + story.should_receive(:tell).and_raise(RuntimeError)
  125 + expect { story.delay.tell }.to raise_error
  126 + end
  127 +
  128 + it "delegates failure hook to object when delay_jobs = false" do
  129 + Delayed::Worker.delay_jobs = false
  130 + method = Delayed::PerformableMethod.new("object", :size, [])
  131 + method.object.should_receive(:failure)
  132 + method.failure
  133 + end
  134 + end
47 135 end
48 136 end
... ...
vendor/plugins/delayed_job/spec/sample_jobs.rb
  1 +class NamedJob < Struct.new(:perform)
  2 + def display_name
  3 + 'named_job'
  4 + end
  5 +end
  6 +
1 7 class SimpleJob
2 8 cattr_accessor :runs; self.runs = 0
3 9 def perform; @@runs += 1; end
... ... @@ -6,20 +12,64 @@ end
6 12 class ErrorJob
7 13 cattr_accessor :runs; self.runs = 0
8 14 def perform; raise 'did not work'; end
9   -end
  15 +end
  16 +
  17 +class CustomRescheduleJob < Struct.new(:offset)
  18 + cattr_accessor :runs; self.runs = 0
  19 + def perform; raise 'did not work'; end
  20 + def reschedule_at(time, attempts); time + offset; end
  21 +end
10 22  
11 23 class LongRunningJob
12 24 def perform; sleep 250; end
13 25 end
14 26  
15 27 class OnPermanentFailureJob < SimpleJob
16   - def on_permanent_failure
17   - end
  28 + def failure; end
  29 + def max_attempts; 1; end
18 30 end
19 31  
20 32 module M
21 33 class ModuleJob
22 34 cattr_accessor :runs; self.runs = 0
23   - def perform; @@runs += 1; end
  35 + def perform; @@runs += 1; end
  36 + end
  37 +end
  38 +
  39 +class CallbackJob
  40 + cattr_accessor :messages
  41 +
  42 + def enqueue(job)
  43 + self.class.messages << 'enqueue'
  44 + end
  45 +
  46 + def before(job)
  47 + self.class.messages << 'before'
  48 + end
  49 +
  50 + def perform
  51 + self.class.messages << 'perform'
  52 + end
  53 +
  54 + def after(job)
  55 + self.class.messages << 'after'
  56 + end
  57 +
  58 + def success(job)
  59 + self.class.messages << 'success'
  60 + end
  61 +
  62 + def error(job, error)
  63 + self.class.messages << "error: #{error.class}"
  64 + end
  65 +
  66 + def failure(job)
  67 + self.class.messages << 'failure'
  68 + end
  69 +end
  70 +
  71 +class EnqueueJobMod < SimpleJob
  72 + def enqueue(job)
  73 + job.run_at = 20.minutes.from_now
24 74 end
25 75 end
... ...
vendor/plugins/delayed_job/spec/setup/active_record.rb
... ... @@ -1,33 +0,0 @@
1   -require 'active_record'
2   -
3   -ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
4   -ActiveRecord::Base.logger = Delayed::Worker.logger
5   -ActiveRecord::Migration.verbose = false
6   -
7   -ActiveRecord::Schema.define do
8   - create_table :delayed_jobs, :force => true do |table|
9   - table.integer :priority, :default => 0
10   - table.integer :attempts, :default => 0
11   - table.text :handler
12   - table.text :last_error
13   - table.datetime :run_at
14   - table.datetime :locked_at
15   - table.datetime :failed_at
16   - table.string :locked_by
17   - table.timestamps
18   - end
19   -
20   - add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
21   -
22   - create_table :stories, :force => true do |table|
23   - table.string :text
24   - end
25   -end
26   -
27   -# Purely useful for test cases...
28   -class Story < ActiveRecord::Base
29   - def tell; text; end
30   - def whatever(n, _); tell*n; end
31   -
32   - handle_asynchronously :whatever
33   -end
vendor/plugins/delayed_job/spec/setup/couch_rest.rb
... ... @@ -1,7 +0,0 @@
1   -require 'couchrest'
2   -require 'delayed/backend/couch_rest'
3   -
4   -Delayed::Backend::CouchRest::Job.use_database CouchRest::Server.new.database!('delayed_job_spec')
5   -
6   -# try to perform a query to check that we can connect
7   -Delayed::Backend::CouchRest::Job.all
8 0 \ No newline at end of file
vendor/plugins/delayed_job/spec/setup/data_mapper.rb
... ... @@ -1,8 +0,0 @@
1   -require 'dm-core'
2   -require 'dm-validations'
3   -
4   -require 'delayed/backend/data_mapper'
5   -
6   -DataMapper.logger = Delayed::Worker.logger
7   -DataMapper.setup(:default, "sqlite3::memory:")
8   -DataMapper.auto_migrate!
9 0 \ No newline at end of file
vendor/plugins/delayed_job/spec/setup/mongo_mapper.rb
... ... @@ -1,17 +0,0 @@
1   -require 'mongo_mapper'
2   -
3   -MongoMapper.config = {
4   - RAILS_ENV => {'database' => 'delayed_job'}
5   -}
6   -MongoMapper.connect RAILS_ENV
7   -
8   -unless defined?(Story)
9   - class Story
10   - include ::MongoMapper::Document
11   - def tell; text; end
12   - def whatever(n, _); tell*n; end
13   - def self.count; end
14   -
15   - handle_asynchronously :whatever
16   - end
17   -end
vendor/plugins/delayed_job/spec/spec_helper.rb
... ... @@ -1,31 +0,0 @@
1   -$:.unshift(File.dirname(__FILE__) + '/../lib')
2   -
3   -require 'rubygems'
4   -require 'spec'
5   -require 'logger'
6   -
7   -gem 'activerecord', ENV['RAILS_VERSION'] if ENV['RAILS_VERSION']
8   -
9   -require 'delayed_job'
10   -require 'sample_jobs'
11   -
12   -Delayed::Worker.logger = Logger.new('/tmp/dj.log')
13   -RAILS_ENV = 'test'
14   -
15   -# determine the available backends
16   -BACKENDS = []
17   -Dir.glob("#{File.dirname(__FILE__)}/setup/*.rb") do |backend|
18   - begin
19   - backend = File.basename(backend, '.rb')
20   - require "setup/#{backend}"
21   - require "backend/#{backend}_job_spec"
22   - BACKENDS << backend.to_sym
23   - rescue Exception
24   - puts "Unable to load #{backend} backend: #{$!}"
25   - end
26   -end
27   -
28   -Delayed::Worker.backend = BACKENDS.first
29   -
30   -# Add this directory so the ActiveSupport autoloading works
31   -ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__)
vendor/plugins/delayed_job/spec/test_backend_spec.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +require 'helper'
  2 +
  3 +describe Delayed::Backend::Test::Job do
  4 + it_should_behave_like 'a delayed_job backend'
  5 +
  6 + describe "#reload" do
  7 + it "causes the payload object to be reloaded" do
  8 + job = "foo".delay.length
  9 + o = job.payload_object
  10 + expect(o.object_id).not_to eq(job.reload.payload_object.object_id)
  11 + end
  12 + end
  13 +end
... ...
vendor/plugins/delayed_job/spec/worker_spec.rb
1   -require 'spec_helper'
  1 +require 'helper'
2 2  
3 3 describe Delayed::Worker do
4   - def job_create(opts = {})
5   - Delayed::Job.create(opts.merge(:payload_object => SimpleJob.new))
6   - end
7   -
8 4 describe "backend=" do
9 5 before do
10 6 @clazz = Class.new
11 7 Delayed::Worker.backend = @clazz
12 8 end
13 9  
14   - it "should set the Delayed::Job constant to the backend" do
15   - Delayed::Job.should == @clazz
  10 + after do
  11 + Delayed::Worker.backend = :test
16 12 end
17   -
18   - it "should set backend with a symbol" do
19   - Delayed::Worker.backend = :active_record
20   - Delayed::Worker.backend.should == Delayed::Backend::ActiveRecord::Job
  13 +
  14 + it "sets the Delayed::Job constant to the backend" do
  15 + expect(Delayed::Job).to eq(@clazz)
  16 + end
  17 +
  18 + it "sets backend with a symbol" do
  19 + Delayed::Worker.backend = :test
  20 + expect(Delayed::Worker.backend).to eq(Delayed::Backend::Test::Job)
21 21 end
22 22 end
23   -
24   - BACKENDS.each do |backend|
25   - describe "with the #{backend} backend" do
26   - before do
27   - Delayed::Worker.backend = backend
28   - Delayed::Job.delete_all
29 23  
30   - @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
  24 + describe "job_say" do
  25 + before do
  26 + @worker = Delayed::Worker.new
  27 + @job = double('job', :id => 123, :name => 'ExampleJob')
  28 + end
31 29  
32   - SimpleJob.runs = 0
33   - end
34   -
35   - describe "running a job" do
36   - it "should fail after Worker.max_run_time" do
37   - begin
38   - old_max_run_time = Delayed::Worker.max_run_time
39   - Delayed::Worker.max_run_time = 1.second
40   - @job = Delayed::Job.create :payload_object => LongRunningJob.new
41   - @worker.run(@job)
42   - @job.reload.last_error.should =~ /expired/
43   - @job.attempts.should == 1
44   - ensure
45   - Delayed::Worker.max_run_time = old_max_run_time
46   - end
47   - end
48   - end
49   -
50   - context "worker prioritization" do
51   - before(:each) do
52   - @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => -5, :quiet => true)
53   - end
  30 + it "logs with job name and id" do
  31 + @worker.should_receive(:say).
  32 + with('Job ExampleJob (id=123) message', Delayed::Worker::DEFAULT_LOG_LEVEL)
  33 + @worker.job_say(@job, 'message')
  34 + end
  35 + end
54 36  
55   - it "should only work_off jobs that are >= min_priority" do
56   - job_create(:priority => -10)
57   - job_create(:priority => 0)
58   - @worker.work_off
  37 + context "worker read-ahead" do
  38 + before do
  39 + @read_ahead = Delayed::Worker.read_ahead
  40 + end
59 41  
60   - SimpleJob.runs.should == 1
61   - end
  42 + after do
  43 + Delayed::Worker.read_ahead = @read_ahead
  44 + end
62 45  
63   - it "should only work_off jobs that are <= max_priority" do
64   - job_create(:priority => 10)
65   - job_create(:priority => 0)
  46 + it "reads five jobs" do
  47 + Delayed::Job.should_receive(:find_available).with(anything, 5, anything).and_return([])
  48 + Delayed::Job.reserve(Delayed::Worker.new)
  49 + end
66 50  
67   - @worker.work_off
  51 + it "reads a configurable number of jobs" do
  52 + Delayed::Worker.read_ahead = 15
  53 + Delayed::Job.should_receive(:find_available).with(anything, Delayed::Worker.read_ahead, anything).and_return([])
  54 + Delayed::Job.reserve(Delayed::Worker.new)
  55 + end
  56 + end
68 57  
69   - SimpleJob.runs.should == 1
70   - end
71   - end
  58 + context "worker exit on complete" do
  59 + before do
  60 + Delayed::Worker.exit_on_complete = true
  61 + end
72 62  
73   - context "while running with locked and expired jobs" do
74   - before(:each) do
75   - @worker.name = 'worker1'
76   - end
77   -
78   - it "should not run jobs locked by another worker" do
79   - job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
80   - lambda { @worker.work_off }.should_not change { SimpleJob.runs }
81   - end
82   -
83   - it "should run open jobs" do
84   - job_create
85   - lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
86   - end
87   -
88   - it "should run expired jobs" do
89   - expired_time = Delayed::Job.db_time_now - (1.minutes + Delayed::Worker.max_run_time)
90   - job_create(:locked_by => 'other_worker', :locked_at => expired_time)
91   - lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
92   - end
93   -
94   - it "should run own jobs" do
95   - job_create(:locked_by => @worker.name, :locked_at => (Delayed::Job.db_time_now - 1.minutes))
96   - lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
97   - end
98   - end
99   -
100   - describe "failed jobs" do
101   - before do
102   - # reset defaults
103   - Delayed::Worker.destroy_failed_jobs = true
104   - Delayed::Worker.max_attempts = 25
105   -
106   - @job = Delayed::Job.enqueue ErrorJob.new
107   - end
108   -
109   - it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
110   - Delayed::Worker.destroy_failed_jobs = false
111   - Delayed::Worker.max_attempts = 1
112   - @worker.run(@job)
113   - @job.reload
114   - @job.last_error.should =~ /did not work/
115   - @job.last_error.should =~ /worker_spec.rb/
116   - @job.attempts.should == 1
117   - @job.failed_at.should_not be_nil
118   - end
119   -
120   - it "should re-schedule jobs after failing" do
121   - @worker.run(@job)
122   - @job.reload
123   - @job.last_error.should =~ /did not work/
124   - @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
125   - @job.attempts.should == 1
126   - @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
127   - @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
128   - end
129   - end
130   -
131   - context "reschedule" do
132   - before do
133   - @job = Delayed::Job.create :payload_object => SimpleJob.new
134   - end
135   -
136   - share_examples_for "any failure more than Worker.max_attempts times" do
137   - context "when the job's payload has an #on_permanent_failure hook" do
138   - before do
139   - @job = Delayed::Job.create :payload_object => OnPermanentFailureJob.new
140   - @job.payload_object.should respond_to :on_permanent_failure
141   - end
142   -
143   - it "should run that hook" do
144   - @job.payload_object.should_receive :on_permanent_failure
145   - Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
146   - end
147   - end
148   -
149   - context "when the job's payload has no #on_permanent_failure hook" do
150   - # It's a little tricky to test this in a straightforward way,
151   - # because putting a should_not_receive expectation on
152   - # @job.payload_object.on_permanent_failure makes that object
153   - # incorrectly return true to
154   - # payload_object.respond_to? :on_permanent_failure, which is what
155   - # reschedule uses to decide whether to call on_permanent_failure.
156   - # So instead, we just make sure that the payload_object as it
157   - # already stands doesn't respond_to? on_permanent_failure, then
158   - # shove it through the iterated reschedule loop and make sure we
159   - # don't get a NoMethodError (caused by calling that nonexistent
160   - # on_permanent_failure method).
161   -
162   - before do
163   - @job.payload_object.should_not respond_to(:on_permanent_failure)
164   - end
165   -
166   - it "should not try to run that hook" do
167   - lambda do
168   - Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
169   - end.should_not raise_exception(NoMethodError)
170   - end
171   - end
172   - end
173   -
174   - context "and we want to destroy jobs" do
175   - before do
176   - Delayed::Worker.destroy_failed_jobs = true
177   - end
178   -
179   - it_should_behave_like "any failure more than Worker.max_attempts times"
180   -
181   - it "should be destroyed if it failed more than Worker.max_attempts times" do
182   - @job.should_receive(:destroy)
183   - Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
184   - end
185   -
186   - it "should not be destroyed if failed fewer than Worker.max_attempts times" do
187   - @job.should_not_receive(:destroy)
188   - (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
189   - end
190   - end
191   -
192   - context "and we don't want to destroy jobs" do
193   - before do
194   - Delayed::Worker.destroy_failed_jobs = false
195   - end
196   -
197   - it_should_behave_like "any failure more than Worker.max_attempts times"
198   -
199   - it "should be failed if it failed more than Worker.max_attempts times" do
200   - @job.reload.failed_at.should == nil
201   - Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
202   - @job.reload.failed_at.should_not == nil
203   - end
204   -
205   - it "should not be failed if it failed fewer than Worker.max_attempts times" do
206   - (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
207   - @job.reload.failed_at.should == nil
208   - end
209   - end
  63 + after do
  64 + Delayed::Worker.exit_on_complete = false
  65 + end
  66 +
  67 + it "exits the loop when no jobs are available" do
  68 + worker = Delayed::Worker.new
  69 + Timeout::timeout(2) do
  70 + worker.start
210 71 end
211 72 end
212 73 end
213   -
  74 +
  75 + context "worker job reservation" do
  76 + before do
  77 + Delayed::Worker.exit_on_complete = true
  78 + end
  79 +
  80 + after do
  81 + Delayed::Worker.exit_on_complete = false
  82 + end
  83 +
  84 + it "handles error during job reservation" do
  85 + Delayed::Job.should_receive(:reserve).and_raise(Exception)
  86 + Delayed::Worker.new.work_off
  87 + end
  88 +
  89 + it "gives up after 10 backend failures" do
  90 + Delayed::Job.stub(:reserve).and_raise(Exception)
  91 + worker = Delayed::Worker.new
  92 + 9.times { worker.work_off }
  93 + expect(lambda { worker.work_off }).to raise_exception
  94 + end
  95 +
  96 + it "allows the backend to attempt recovery from reservation errors" do
  97 + Delayed::Job.should_receive(:reserve).and_raise(Exception)
  98 + Delayed::Job.should_receive(:recover_from).with(instance_of(Exception))
  99 + Delayed::Worker.new.work_off
  100 + end
  101 + end
214 102 end
... ...
vendor/plugins/delayed_job/spec/yaml_ext_spec.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +require 'helper'
  2 +
  3 +describe "YAML" do
  4 + it "autoloads classes" do
  5 + expect {
  6 + yaml = "--- !ruby/class Autoloaded::Clazz\n"
  7 + expect(YAML.load(yaml)).to eq(Autoloaded::Clazz)
  8 + }.not_to raise_error
  9 + end
  10 +
  11 + it "autoloads the class of a struct" do
  12 + expect {
  13 + yaml = "--- !ruby/class Autoloaded::Struct\n"
  14 + expect(YAML.load(yaml)).to eq(Autoloaded::Struct)
  15 + }.not_to raise_error
  16 + end
  17 +
  18 + it "autoloads the class for the instance of a struct" do
  19 + expect {
  20 + yaml = "--- !ruby/struct:Autoloaded::InstanceStruct {}"
  21 + expect(YAML.load(yaml).class).to eq(Autoloaded::InstanceStruct)
  22 + }.not_to raise_error
  23 + end
  24 +
  25 + it "autoloads the class for the instance" do
  26 + expect {
  27 + yaml = "--- !ruby/object:Autoloaded::InstanceClazz {}\n"
  28 + expect(YAML.load(yaml).class).to eq(Autoloaded::InstanceClazz)
  29 + }.not_to raise_error
  30 + end
  31 +
  32 + it "does not throw an uninitialized constant Syck::Syck when using YAML.load with poorly formed yaml" do
  33 + expect{ YAML.load(YAML.dump("foo: *bar"))}.not_to raise_error
  34 + end
  35 +end
... ...
vendor/plugins/delayed_job/tasks/jobs.rake
... ... @@ -1 +0,0 @@
1   -require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'tasks'))
vendor/plugins/delayed_job_active_record/.rspec 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +--color
  2 +--fail-fast
... ...
vendor/plugins/delayed_job_active_record/.travis.yml 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +language: ruby
  2 +before_script:
  3 + - mysql -e 'create database delayed_job_test;'
  4 + - psql -c 'create database delayed_job_test;' -U postgres
  5 +script: bundle exec rspec
  6 +gemfile:
  7 + - gemfiles/mysql/3-0.gemfile
  8 + - gemfiles/mysql/3-1.gemfile
  9 + - gemfiles/mysql/3-2.gemfile
  10 + - gemfiles/mysql/4-0.gemfile
  11 + - gemfiles/postgresql/3-0.gemfile
  12 + - gemfiles/postgresql/3-1.gemfile
  13 + - gemfiles/postgresql/3-2.gemfile
  14 + - gemfiles/postgresql/4-0.gemfile
  15 + - gemfiles/sqlite3/3-0.gemfile
  16 + - gemfiles/sqlite3/3-1.gemfile
  17 + - gemfiles/sqlite3/3-2.gemfile
  18 + - gemfiles/sqlite3/4-0.gemfile
  19 + - gemfiles/sqlite3/4-0-protected_attributes.gemfile
  20 +rvm:
  21 + - rbx-19mode
  22 + - jruby-19mode
  23 + - 1.9.3
  24 + - 2.0.0
  25 +matrix:
  26 + allow_failures:
  27 + - rvm: rbx-19mode
  28 + - rvm: jruby-19mode
... ...
vendor/plugins/delayed_job_active_record/CONTRIBUTING.md 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +## How to contribute
  2 +
  3 +If you find what looks like a bug:
  4 +
  5 +* Search the [mailing list](http://groups.google.com/group/delayed_job) to see if anyone else had the same issue.
  6 +* Check the [GitHub issue tracker](http://github.com/collectiveidea/delayed_job_active_record/issues/) to see if anyone else has reported issue.
  7 +* If you don't see anything, create an issue with information on how to reproduce it.
  8 +
  9 +If you want to contribute an enhancement or a fix:
  10 +
  11 +* Fork the project on github.
  12 +* Make your changes with tests.
  13 +* Commit the changes without making changes to the Rakefile or any other files that aren't related to your enhancement or fix
  14 +* Send a pull request.
... ...
vendor/plugins/delayed_job_active_record/Gemfile 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbcmysql-adapter'
  8 + gem 'jdbc-mysql'
  9 +
  10 + gem 'activerecord-jdbcpostgresql-adapter'
  11 + gem 'jdbc-postgres'
  12 +
  13 + gem 'activerecord-jdbcsqlite3-adapter'
  14 + gem 'jdbc-sqlite3'
  15 + end
  16 +
  17 + platforms :ruby, :mswin, :mingw do
  18 + gem 'mysql', '~> 2.8.1'
  19 + gem 'pg'
  20 + gem 'sqlite3'
  21 + end
  22 +
  23 + gem 'coveralls', :require => false
  24 + gem 'rspec', '>= 2.11'
  25 + gem 'simplecov', :require => false
  26 +end
  27 +
  28 +gemspec
... ...
vendor/plugins/delayed_job_active_record/LICENSE.md 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +Copyright (c) 2005 Tobias Lütke
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
  17 +NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
... ...
vendor/plugins/delayed_job_active_record/README.md 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +# DelayedJob ActiveRecord Backend
  2 +
  3 +[![Gem Version](https://badge.fury.io/rb/delayed_job_active_record.png)](https://rubygems.org/gems/delayed_job_active_record)
  4 +[![Build Status](https://travis-ci.org/collectiveidea/delayed_job_active_record.png)](https://travis-ci.org/collectiveidea/delayed_job_active_record)
  5 +[![Dependency Status](https://gemnasium.com/collectiveidea/delayed_job_active_record.png)](https://gemnasium.com/collectiveidea/delayed_job_active_record)
  6 +[![Code Climate](https://codeclimate.com/github/collectiveidea/delayed_job_active_record.png)](https://codeclimate.com/github/collectiveidea/delayed_job_active_record)
  7 +[![Coverage Status](https://coveralls.io/repos/collectiveidea/delayed_job_active_record/badge.png?branch=master)](https://coveralls.io/r/collectiveidea/delayed_job_active_record)
  8 +
  9 +## Installation
  10 +
  11 +Add the gem to your Gemfile:
  12 +
  13 + gem 'delayed_job_active_record'
  14 +
  15 +Run `bundle install`.
  16 +
  17 +If you're using Rails, run the generator to create the migration for the
  18 +delayed_job table.
  19 +
  20 + rails g delayed_job:active_record
  21 + rake db:migrate
  22 +
  23 +## Upgrading from 2.x to 3.0.0
  24 +
  25 +If you're upgrading from Delayed Job 2.x, run the upgrade generator to create a
  26 +migration to add a column to your delayed_jobs table.
  27 +
  28 + rails g delayed_job:upgrade
  29 + rake db:migrate
  30 +
  31 +That's it. Use [delayed_job as normal](http://github.com/collectiveidea/delayed_job).
... ...
vendor/plugins/delayed_job_active_record/Rakefile 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +# -*- encoding: utf-8 -*-
  2 +require "bundler/gem_helper"
  3 +Bundler::GemHelper.install_tasks
  4 +
  5 +require "rspec/core/rake_task"
  6 +
  7 +ADAPTERS = %w(mysql postgresql sqlite3)
  8 +
  9 +ADAPTERS.each do |adapter|
  10 + desc "Run RSpec code examples for #{adapter} adapter"
  11 + RSpec::Core::RakeTask.new(adapter => "#{adapter}:adapter")
  12 +
  13 + namespace adapter do
  14 + task :adapter do
  15 + ENV["ADAPTER"] = adapter
  16 + end
  17 + end
  18 +end
  19 +
  20 +task :coverage do
  21 + ENV["COVERAGE"] = "true"
  22 +end
  23 +
  24 +task :adapter do
  25 + ENV["ADAPTER"] = nil
  26 +end
  27 +
  28 +Rake::Task[:spec].enhance do
  29 + require "simplecov"
  30 + require "coveralls"
  31 +
  32 + Coveralls::SimpleCov::Formatter.new.format(SimpleCov.result)
  33 +end
  34 +
  35 +task default: ([:coverage] + ADAPTERS + [:adapter])
... ...
vendor/plugins/delayed_job_active_record/delayed_job_active_record.gemspec 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +# coding: utf-8
  2 +
  3 +Gem::Specification.new do |spec|
  4 + spec.add_dependency 'activerecord', ['>= 3.0', '< 4.1']
  5 + spec.add_dependency 'delayed_job', ['>= 3.0', '< 4.1']
  6 + spec.authors = ["Brian Ryckbost", "Matt Griffin", "Erik Michaels-Ober"]
  7 + spec.description = 'ActiveRecord backend for Delayed::Job, originally authored by Tobias Lütke'
  8 + spec.email = ['bryckbost@gmail.com', 'matt@griffinonline.org', 'sferik@gmail.com']
  9 + spec.files = %w(CONTRIBUTING.md LICENSE.md README.md Rakefile delayed_job_active_record.gemspec)
  10 + spec.files += Dir.glob("lib/**/*.rb")
  11 + spec.files += Dir.glob("spec/**/*")
  12 + spec.homepage = 'http://github.com/collectiveidea/delayed_job_active_record'
  13 + spec.licenses = ['MIT']
  14 + spec.name = 'delayed_job_active_record'
  15 + spec.require_paths = ['lib']
  16 + spec.summary = 'ActiveRecord backend for DelayedJob'
  17 + spec.test_files = Dir.glob("spec/**/*")
  18 + spec.version = '4.0.0'
  19 +end
... ...
vendor/plugins/delayed_job_active_record/gemfiles/mysql/3-0.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcmysql-adapter'
  9 + gem 'jdbc-mysql'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'mysql', '~> 2.8.1'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.0.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/mysql/3-1.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcmysql-adapter'
  9 + gem 'jdbc-mysql'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'mysql', '~> 2.8.1'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.1.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/mysql/3-2.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcmysql-adapter'
  9 + gem 'jdbc-mysql'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'mysql', '~> 2.8.1'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.2.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/mysql/4-0.gemfile 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcmysql-adapter'
  9 + gem 'jdbc-mysql'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'mysql', '~> 2.9'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 4.0.0.beta"
  21 +
  22 + gem 'delayed_job', "~> 4.0.0.beta"
  23 +end
  24 +
  25 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/postgresql/3-0.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcpostgresql-adapter'
  9 + gem 'jdbc-postgres'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'pg'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.0.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/postgresql/3-1.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcpostgresql-adapter'
  9 + gem 'jdbc-postgres'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'pg'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.1.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/postgresql/3-2.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcpostgresql-adapter'
  9 + gem 'jdbc-postgres'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'pg'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.2.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/postgresql/4-0.gemfile 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'activerecord-jdbc-adapter'
  8 + gem 'activerecord-jdbcpostgresql-adapter'
  9 + gem 'jdbc-postgres'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'pg'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 4.0.0.beta"
  21 +
  22 + gem 'delayed_job', "~> 4.0.0.beta"
  23 +end
  24 +
  25 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/sqlite3/3-0.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'jruby-openssl'
  8 + gem 'activerecord-jdbc-adapter'
  9 + gem 'activerecord-jdbcsqlite3-adapter'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'sqlite3'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.0.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/sqlite3/3-1.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'jruby-openssl'
  8 + gem 'activerecord-jdbc-adapter'
  9 + gem 'activerecord-jdbcsqlite3-adapter'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'sqlite3'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.1.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/sqlite3/3-2.gemfile 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'jruby-openssl'
  8 + gem 'activerecord-jdbc-adapter'
  9 + gem 'activerecord-jdbcsqlite3-adapter'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'sqlite3'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 3.2.0"
  21 +end
  22 +
  23 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/sqlite3/4-0-protected_attributes.gemfile 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'jruby-openssl'
  8 + gem 'activerecord-jdbc-adapter'
  9 + gem 'activerecord-jdbcsqlite3-adapter'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'sqlite3'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11', :require => false
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 4.0.0.beta"
  21 + gem 'protected_attributes'
  22 +
  23 + gem 'delayed_job', "~> 4.0.0.beta", :require => false
  24 +end
  25 +
  26 +gemspec :path => "../../"
... ...
vendor/plugins/delayed_job_active_record/gemfiles/sqlite3/4-0.gemfile 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'rake'
  4 +
  5 +group :test do
  6 + platforms :jruby do
  7 + gem 'jruby-openssl'
  8 + gem 'activerecord-jdbc-adapter'
  9 + gem 'activerecord-jdbcsqlite3-adapter'
  10 + end
  11 +
  12 + platforms :ruby, :mswin, :mingw do
  13 + gem 'sqlite3'
  14 + end
  15 +
  16 + gem 'coveralls', :require => false
  17 + gem 'rspec', '>= 2.11'
  18 + gem 'simplecov', :require => false
  19 +
  20 + gem 'activerecord', "~> 4.0.0.beta"
  21 +
  22 + gem 'delayed_job', "~> 4.0.0.beta"
  23 +end
  24 +
  25 +gemspec :path => "../../"
... ...