delayed_job 1.9.0pre → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,30 +40,32 @@ After delayed_job is installed, you will need to setup the backend.
40
40
 
41
41
  h2. Backends
42
42
 
43
- delayed_job supports multiple backends for storing the job queue. The default is Active Record, which requires a jobs table.
43
+ delayed_job supports multiple backends for storing the job queue. There are currently implementations for Active Record, MongoMapper, and DataMapper.
44
+
45
+ h3. Active Record
46
+
47
+ The default is Active Record, which requires a jobs table.
44
48
 
45
49
  <pre>
46
- script/generate delayed_job
47
- rake db:migrate
50
+ $ script/generate delayed_job
51
+ $ rake db:migrate
48
52
  </pre>
49
53
 
50
- You can change the backend in an initializer:
54
+ h3. MongoMapper
51
55
 
52
56
  <pre>
53
57
  # config/initializers/delayed_job.rb
54
58
  Delayed::Worker.backend = :mongo_mapper
55
59
  </pre>
56
60
 
57
- h2. Upgrading to 1.8
58
-
59
- If you are upgrading from a previous release, you will need to generate the new @script/delayed_job@:
61
+ h3. DataMapper
60
62
 
61
63
  <pre>
62
- script/generate delayed_job --skip-migration
64
+ # config/initializers/delayed_job.rb
65
+ Delayed::Worker.backend = :data_mapper
66
+ Delayed::Worker.backend.auto_upgrade!
63
67
  </pre>
64
68
 
65
- Known Issues: script/delayed_job does not work properly with anything besides the Active Record backend. That will be resolved before the next gem release.
66
-
67
69
  h2. Queuing Jobs
68
70
 
69
71
  Call @#send_later(method, params)@ on any object and it will be processed in the background.
@@ -92,7 +94,7 @@ device.deliver
92
94
 
93
95
  h2. Running Jobs
94
96
 
95
- @script/delayed_job@ can be used to manage a background process which will start working off jobs.
97
+ @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`.
96
98
 
97
99
  <pre>
98
100
  $ RAILS_ENV=production script/delayed_job start
data/Rakefile CHANGED
@@ -18,11 +18,17 @@ Jeweler::Tasks.new do |s|
18
18
  s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
19
19
  s.extra_rdoc_files = ["README.textile"]
20
20
 
21
- s.test_files = Dir['spec/**/*']
21
+ s.test_files = Dir['spec/*_spec.rb']
22
22
 
23
23
  s.add_dependency "daemons"
24
24
  s.add_development_dependency "rspec"
25
25
  s.add_development_dependency "sqlite3-ruby"
26
+ s.add_development_dependency "mongo_mapper"
27
+ s.add_development_dependency "dm-core"
28
+ s.add_development_dependency "dm-observer"
29
+ s.add_development_dependency "dm-aggregates"
30
+ s.add_development_dependency "do_sqlite3"
31
+ s.add_development_dependency "database_cleaner"
26
32
  end
27
33
 
28
34
  require 'spec/rake/spectask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.9.0pre
1
+ 2.0.0
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib')
2
+ require 'rubygems'
3
+ require 'logger'
4
+ require 'delayed_job'
5
+ require 'benchmark'
6
+
7
+ Delayed::Worker.logger = Logger.new('/dev/null')
8
+
9
+ Benchmark.bm(10) do |x|
10
+ [:active_record, :mongo_mapper, :data_mapper].each do |backend|
11
+ require "spec/setup/#{backend}"
12
+ Delayed::Worker.backend = backend
13
+
14
+ n = 10000
15
+ n.times { "foo".send_later :length }
16
+
17
+ x.report(backend.to_s) { Delayed::Worker.new(:quiet => true).work_off(n) }
18
+ end
19
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{delayed_job}
8
- s.version = "1.9.0pre"
8
+ s.version = "2.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brandon Keepers", "Tobias L\303\274tke"]
12
- s.date = %q{2010-03-26}
12
+ s.date = %q{2010-04-03}
13
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
14
 
15
15
  This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job).}
@@ -23,6 +23,7 @@ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)
23
23
  "README.textile",
24
24
  "Rakefile",
25
25
  "VERSION",
26
+ "benchmarks.rb",
26
27
  "contrib/delayed_job.monitrc",
27
28
  "delayed_job.gemspec",
28
29
  "generators/delayed_job/delayed_job_generator.rb",
@@ -30,6 +31,7 @@ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)
30
31
  "generators/delayed_job/templates/script",
31
32
  "lib/delayed/backend/active_record.rb",
32
33
  "lib/delayed/backend/base.rb",
34
+ "lib/delayed/backend/data_mapper.rb",
33
35
  "lib/delayed/backend/mongo_mapper.rb",
34
36
  "lib/delayed/command.rb",
35
37
  "lib/delayed/message_sending.rb",
@@ -41,12 +43,14 @@ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)
41
43
  "rails/init.rb",
42
44
  "recipes/delayed_job.rb",
43
45
  "spec/backend/active_record_job_spec.rb",
46
+ "spec/backend/data_mapper_job_spec.rb",
44
47
  "spec/backend/mongo_mapper_job_spec.rb",
45
48
  "spec/backend/shared_backend_spec.rb",
46
49
  "spec/delayed_method_spec.rb",
47
50
  "spec/performable_method_spec.rb",
48
51
  "spec/sample_jobs.rb",
49
52
  "spec/setup/active_record.rb",
53
+ "spec/setup/data_mapper.rb",
50
54
  "spec/setup/mongo_mapper.rb",
51
55
  "spec/spec_helper.rb",
52
56
  "spec/story_spec.rb",
@@ -56,20 +60,11 @@ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)
56
60
  s.homepage = %q{http://github.com/collectiveidea/delayed_job}
57
61
  s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
58
62
  s.require_paths = ["lib"]
59
- s.rubygems_version = %q{1.3.5}
63
+ s.rubygems_version = %q{1.3.6}
60
64
  s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}
61
65
  s.test_files = [
62
- "spec/backend",
63
- "spec/backend/active_record_job_spec.rb",
64
- "spec/backend/mongo_mapper_job_spec.rb",
65
- "spec/backend/shared_backend_spec.rb",
66
- "spec/delayed_method_spec.rb",
66
+ "spec/delayed_method_spec.rb",
67
67
  "spec/performable_method_spec.rb",
68
- "spec/sample_jobs.rb",
69
- "spec/setup",
70
- "spec/setup/active_record.rb",
71
- "spec/setup/mongo_mapper.rb",
72
- "spec/spec_helper.rb",
73
68
  "spec/story_spec.rb",
74
69
  "spec/worker_spec.rb"
75
70
  ]
@@ -82,15 +77,33 @@ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)
82
77
  s.add_runtime_dependency(%q<daemons>, [">= 0"])
83
78
  s.add_development_dependency(%q<rspec>, [">= 0"])
84
79
  s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
80
+ s.add_development_dependency(%q<mongo_mapper>, [">= 0"])
81
+ s.add_development_dependency(%q<dm-core>, [">= 0"])
82
+ s.add_development_dependency(%q<dm-observer>, [">= 0"])
83
+ s.add_development_dependency(%q<dm-aggregates>, [">= 0"])
84
+ s.add_development_dependency(%q<do_sqlite3>, [">= 0"])
85
+ s.add_development_dependency(%q<database_cleaner>, [">= 0"])
85
86
  else
86
87
  s.add_dependency(%q<daemons>, [">= 0"])
87
88
  s.add_dependency(%q<rspec>, [">= 0"])
88
89
  s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
90
+ s.add_dependency(%q<mongo_mapper>, [">= 0"])
91
+ s.add_dependency(%q<dm-core>, [">= 0"])
92
+ s.add_dependency(%q<dm-observer>, [">= 0"])
93
+ s.add_dependency(%q<dm-aggregates>, [">= 0"])
94
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
95
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
89
96
  end
90
97
  else
91
98
  s.add_dependency(%q<daemons>, [">= 0"])
92
99
  s.add_dependency(%q<rspec>, [">= 0"])
93
100
  s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
101
+ s.add_dependency(%q<mongo_mapper>, [">= 0"])
102
+ s.add_dependency(%q<dm-core>, [">= 0"])
103
+ s.add_dependency(%q<dm-observer>, [">= 0"])
104
+ s.add_dependency(%q<dm-aggregates>, [">= 0"])
105
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
106
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
94
107
  end
95
108
  end
96
109
 
@@ -28,6 +28,11 @@ module Delayed
28
28
  # Hook method that is called after a new worker is forked
29
29
  def after_fork
30
30
  end
31
+
32
+ def work_off(num = 100)
33
+ warn "[DEPRECATION] `Delayed::Job.work_off` is deprecated. Use `Delayed::Worker.new.work_off instead."
34
+ Delayed::Worker.new.work_off(num)
35
+ end
31
36
  end
32
37
 
33
38
  ParseObjectFromYaml = /\!ruby\/\w+\:([^\s]+)/
@@ -0,0 +1,124 @@
1
+ require 'dm-core'
2
+ require 'dm-observer'
3
+ require 'dm-aggregates'
4
+
5
+ module DataMapper
6
+ module Resource
7
+ module ClassMethods
8
+ def load_for_delayed_job(id)
9
+ find!(id)
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def dump_for_delayed_job
15
+ "#{self.class};#{id}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Delayed
22
+ module Backend
23
+ module DataMapper
24
+ class Job
25
+ include ::DataMapper::Resource
26
+ include Delayed::Backend::Base
27
+
28
+ storage_names[:default] = 'delayed_jobs'
29
+
30
+ property :id, Serial
31
+ property :priority, Integer, :default => 0
32
+ property :attempts, Integer, :default => 0
33
+ property :handler, String
34
+ property :run_at, Time
35
+ property :locked_at, Time
36
+ property :locked_by, String
37
+ property :failed_at, Time
38
+ property :last_error, String
39
+
40
+ def self.db_time_now
41
+ Time.now
42
+ end
43
+
44
+ def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
45
+
46
+ simple_conditions = { :run_at.lte => db_time_now, :limit => limit, :failed_at => nil, :order => [:priority.asc, :run_at.asc] }
47
+
48
+ # respect priorities
49
+ simple_conditions[:priority.gte] = Worker.min_priority if Worker.min_priority
50
+ simple_conditions[:priority.lte] = Worker.max_priority if Worker.max_priority
51
+
52
+ # lockable
53
+ lockable = (
54
+ # not locked or past the max time
55
+ ( all(:locked_at => nil ) | all(:locked_at.lt => db_time_now - max_run_time)) |
56
+
57
+ # OR locked by our worker
58
+ all(:locked_by => worker_name))
59
+
60
+ # plus some other boring junk
61
+ (lockable).all( simple_conditions )
62
+ end
63
+
64
+ # When a worker is exiting, make sure we don't have any locked jobs.
65
+ def self.clear_locks!(worker_name)
66
+ all(:locked_by => worker_name).update(:locked_at => nil, :locked_by => nil)
67
+ end
68
+
69
+ # Lock this job for this worker.
70
+ # Returns true if we have the lock, false otherwise.
71
+ def lock_exclusively!(max_run_time, worker = worker_name)
72
+ now = self.class.db_time_now
73
+ overtime = now - max_run_time
74
+
75
+ # FIXME - this is a bit gross
76
+ # DM doesn't give us the number of rows affected by a collection update
77
+ # so we have to circumvent some niceness in DM::Collection here
78
+ collection = locked_by != worker ?
79
+ (self.class.all(:id => id, :run_at.lte => now) & ( self.class.all(:locked_at => nil) | self.class.all(:locked_at.lt => overtime) ) ) :
80
+ self.class.all(:id => id, :locked_by => worker)
81
+
82
+ attributes = collection.model.new(:locked_at => now, :locked_by => worker).dirty_attributes
83
+ affected_rows = self.repository.update(attributes, collection)
84
+
85
+ if affected_rows == 1
86
+ self.locked_at = now
87
+ self.locked_by = worker
88
+ return true
89
+ else
90
+ return false
91
+ end
92
+ end
93
+
94
+ # these are common to the other backends, so we provide an implementation
95
+ def self.delete_all
96
+ Delayed::Job.auto_migrate!
97
+ end
98
+
99
+ def self.find id
100
+ get id
101
+ end
102
+
103
+ def update_attributes(attributes)
104
+ attributes.each do |k,v|
105
+ self[k] = v
106
+ end
107
+ self.save
108
+ end
109
+
110
+
111
+ end
112
+
113
+ class JobObserver
114
+ include ::DataMapper::Observer
115
+
116
+ observe Job
117
+
118
+ before :save do
119
+ self.run_at ||= self.class.db_time_now
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,15 +1,14 @@
1
1
  require 'spec_helper'
2
+ require 'backend/shared_backend_spec'
2
3
  require 'delayed/backend/active_record'
3
4
 
4
- describe Delayed::Job do
5
+ describe Delayed::Backend::ActiveRecord::Job do
5
6
  before(:all) do
6
- @backend = Delayed::Job
7
+ @backend = Delayed::Backend::ActiveRecord::Job
7
8
  end
8
9
 
9
10
  before(:each) do
10
- Delayed::Worker.max_priority = nil
11
- Delayed::Worker.min_priority = nil
12
- Delayed::Job.delete_all
11
+ Delayed::Backend::ActiveRecord::Job.delete_all
13
12
  SimpleJob.runs = 0
14
13
  end
15
14
 
@@ -28,14 +27,13 @@ describe Delayed::Job do
28
27
  it "should return UTC time if that is the AR default" do
29
28
  Time.zone = nil
30
29
  ActiveRecord::Base.default_timezone = :utc
31
- Delayed::Job.db_time_now.zone.should == 'UTC'
30
+ Delayed::Backend::ActiveRecord::Job.db_time_now.zone.should == 'UTC'
32
31
  end
33
32
 
34
33
  it "should return local time if that is the AR default" do
35
34
  Time.zone = 'Central Time (US & Canada)'
36
35
  ActiveRecord::Base.default_timezone = :local
37
- %w(CST CDT).should include(Delayed::Job.db_time_now.zone)
36
+ %w(CST CDT).should include(Delayed::Backend::ActiveRecord::Job.db_time_now.zone)
38
37
  end
39
- end
40
-
38
+ end
41
39
  end
@@ -0,0 +1,16 @@
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
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
-
2
+ require 'backend/shared_backend_spec'
3
3
  require 'delayed/backend/mongo_mapper'
4
4
 
5
5
  describe Delayed::Backend::MongoMapper::Job do
@@ -4,6 +4,8 @@ shared_examples_for 'a backend' do
4
4
  end
5
5
 
6
6
  before do
7
+ Delayed::Worker.max_priority = nil
8
+ Delayed::Worker.min_priority = nil
7
9
  SimpleJob.runs = 0
8
10
  end
9
11
 
@@ -1,27 +1,27 @@
1
1
  require 'active_record'
2
2
 
3
3
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
4
- ActiveRecord::Base.logger = DELAYED_JOB_LOGGER
4
+ ActiveRecord::Base.logger = Delayed::Worker.logger
5
5
  ActiveRecord::Migration.verbose = false
6
6
 
7
7
  ActiveRecord::Schema.define do
8
-
9
8
  create_table :delayed_jobs, :force => true do |table|
10
9
  table.integer :priority, :default => 0
11
10
  table.integer :attempts, :default => 0
12
11
  table.text :handler
13
- table.string :last_error
12
+ table.text :last_error
14
13
  table.datetime :run_at
15
14
  table.datetime :locked_at
16
- table.string :locked_by
17
15
  table.datetime :failed_at
16
+ table.string :locked_by
18
17
  table.timestamps
19
18
  end
20
19
 
20
+ add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
21
+
21
22
  create_table :stories, :force => true do |table|
22
23
  table.string :text
23
24
  end
24
-
25
25
  end
26
26
 
27
27
  # Purely useful for test cases...
@@ -0,0 +1,6 @@
1
+ require 'dm-core'
2
+ require 'delayed/backend/data_mapper'
3
+
4
+ DataMapper.logger = Delayed::Worker.logger
5
+ DataMapper.setup(:default, "sqlite3::memory:")
6
+ DataMapper.auto_migrate!
@@ -1,4 +1,6 @@
1
- MongoMapper.connection = Mongo::Connection.new nil, nil, :logger => DELAYED_JOB_LOGGER
1
+ require 'mongo_mapper'
2
+
3
+ MongoMapper.connection = Mongo::Connection.new nil, nil, :logger => Delayed::Worker.logger
2
4
  MongoMapper.database = 'delayed_job'
3
5
 
4
6
  unless defined?(Story)
@@ -7,7 +9,7 @@ unless defined?(Story)
7
9
  def tell; text; end
8
10
  def whatever(n, _); tell*n; end
9
11
  def self.count; end
10
-
12
+
11
13
  handle_asynchronously :whatever
12
14
  end
13
15
  end
@@ -4,32 +4,22 @@ require 'rubygems'
4
4
  require 'spec'
5
5
  require 'logger'
6
6
 
7
- backends_available = []
8
- %w(active_record mongo_mapper).each do |backend|
9
- begin
10
- require backend
11
- backends_available << backend
12
- rescue LoadError => e
13
- $stderr.puts "The backend '#{backend}' is not available. Skipping tests"
14
- end
15
- end
16
-
17
- if backends_available.empty?
18
- raise LoadError, "Cannot run delayed_job specs. No backends available"
19
- end
20
-
21
7
  require 'delayed_job'
22
8
  require 'sample_jobs'
23
- require 'backend/shared_backend_spec'
24
9
 
25
- DELAYED_JOB_LOGGER = Logger.new('/tmp/dj.log')
26
- Delayed::Worker.logger = DELAYED_JOB_LOGGER
10
+ Delayed::Worker.logger = Logger.new('/tmp/dj.log')
27
11
 
28
- DEFAULT_BACKEND = backends_available.first.to_sym
29
-
30
- Delayed::Worker.backend = DEFAULT_BACKEND
31
-
32
- backends_available.each do |backend|
33
- require "setup/#{backend}"
34
- require "backend/#{backend}_job_spec"
12
+ # determine the available backends
13
+ BACKENDS = []
14
+ Dir.glob("#{File.dirname(__FILE__)}/setup/*.rb") do |backend|
15
+ begin
16
+ backend = File.basename(backend, '.rb')
17
+ require "setup/#{backend}"
18
+ require "backend/#{backend}_job_spec"
19
+ BACKENDS << backend.to_sym
20
+ rescue LoadError
21
+ puts "Unable to load #{backend} backend! #{$!}"
22
+ end
35
23
  end
24
+
25
+ Delayed::Worker.backend = BACKENDS.first
@@ -5,21 +5,6 @@ describe Delayed::Worker do
5
5
  Delayed::Job.create(opts.merge(:payload_object => SimpleJob.new))
6
6
  end
7
7
 
8
- before(:all) do
9
- Delayed::Worker.send :public, :work_off
10
- end
11
-
12
- before(:each) do
13
- # Make sure backend is set to active record
14
- Delayed::Worker.backend = DEFAULT_BACKEND
15
-
16
- @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
17
-
18
- Delayed::Job.delete_all
19
-
20
- SimpleJob.runs = 0
21
- end
22
-
23
8
  describe "backend=" do
24
9
  it "should set the Delayed::Job constant to the backend" do
25
10
  @clazz = Class.new
@@ -34,145 +19,157 @@ describe Delayed::Worker do
34
19
  end
35
20
  end
36
21
 
37
- describe "running a job" do
38
- it "should fail after Worker.max_run_time" do
39
- begin
40
- old_max_run_time = Delayed::Worker.max_run_time
41
- Delayed::Worker.max_run_time = 1.second
42
- @job = Delayed::Job.create :payload_object => LongRunningJob.new
43
- @worker.run(@job)
44
- @job.reload.last_error.should =~ /expired/
45
- @job.attempts.should == 1
46
- ensure
47
- Delayed::Worker.max_run_time = old_max_run_time
22
+ BACKENDS.each do |backend|
23
+ describe "with the #{backend} backend" do
24
+ before do
25
+ Delayed::Worker.backend = backend
26
+ Delayed::Job.delete_all
27
+
28
+ @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
29
+
30
+ SimpleJob.runs = 0
48
31
  end
49
- end
50
- end
51
32
 
52
- context "worker prioritization" do
53
- before(:each) do
54
- @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => -5, :quiet => true)
55
- end
33
+ describe "running a job" do
34
+ it "should fail after Worker.max_run_time" do
35
+ begin
36
+ old_max_run_time = Delayed::Worker.max_run_time
37
+ Delayed::Worker.max_run_time = 1.second
38
+ @job = Delayed::Job.create :payload_object => LongRunningJob.new
39
+ @worker.run(@job)
40
+ @job.reload.last_error.should =~ /expired/
41
+ @job.attempts.should == 1
42
+ ensure
43
+ Delayed::Worker.max_run_time = old_max_run_time
44
+ end
45
+ end
46
+ end
47
+
48
+ context "worker prioritization" do
49
+ before(:each) do
50
+ @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => -5, :quiet => true)
51
+ end
56
52
 
57
- it "should only work_off jobs that are >= min_priority" do
58
- SimpleJob.runs.should == 0
53
+ it "should only work_off jobs that are >= min_priority" do
54
+ SimpleJob.runs.should == 0
59
55
 
60
- job_create(:priority => -10)
61
- job_create(:priority => 0)
62
- @worker.work_off
56
+ job_create(:priority => -10)
57
+ job_create(:priority => 0)
58
+ @worker.work_off
63
59
 
64
- SimpleJob.runs.should == 1
65
- end
60
+ SimpleJob.runs.should == 1
61
+ end
66
62
 
67
- it "should only work_off jobs that are <= max_priority" do
68
- SimpleJob.runs.should == 0
63
+ it "should only work_off jobs that are <= max_priority" do
64
+ SimpleJob.runs.should == 0
69
65
 
70
- job_create(:priority => 10)
71
- job_create(:priority => 0)
66
+ job_create(:priority => 10)
67
+ job_create(:priority => 0)
72
68
 
73
- @worker.work_off
69
+ @worker.work_off
74
70
 
75
- SimpleJob.runs.should == 1
76
- end
77
- end
71
+ SimpleJob.runs.should == 1
72
+ end
73
+ end
78
74
 
79
- context "while running with locked and expired jobs" do
80
- before(:each) do
81
- @worker.name = 'worker1'
82
- end
75
+ context "while running with locked and expired jobs" do
76
+ before(:each) do
77
+ @worker.name = 'worker1'
78
+ end
83
79
 
84
- it "should not run jobs locked by another worker" do
85
- job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
86
- lambda { @worker.work_off }.should_not change { SimpleJob.runs }
87
- end
80
+ it "should not run jobs locked by another worker" do
81
+ job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
82
+ lambda { @worker.work_off }.should_not change { SimpleJob.runs }
83
+ end
88
84
 
89
- it "should run open jobs" do
90
- job_create
91
- lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
92
- end
85
+ it "should run open jobs" do
86
+ job_create
87
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
88
+ end
93
89
 
94
- it "should run expired jobs" do
95
- expired_time = Delayed::Job.db_time_now - (1.minutes + Delayed::Worker.max_run_time)
96
- job_create(:locked_by => 'other_worker', :locked_at => expired_time)
97
- lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
98
- end
90
+ it "should run expired jobs" do
91
+ expired_time = Delayed::Job.db_time_now - (1.minutes + Delayed::Worker.max_run_time)
92
+ job_create(:locked_by => 'other_worker', :locked_at => expired_time)
93
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
94
+ end
99
95
 
100
- it "should run own jobs" do
101
- job_create(:locked_by => @worker.name, :locked_at => (Delayed::Job.db_time_now - 1.minutes))
102
- lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
103
- end
104
- end
96
+ it "should run own jobs" do
97
+ job_create(:locked_by => @worker.name, :locked_at => (Delayed::Job.db_time_now - 1.minutes))
98
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
99
+ end
100
+ end
105
101
 
106
- describe "failed jobs" do
107
- before do
108
- # reset defaults
109
- Delayed::Worker.destroy_failed_jobs = true
110
- Delayed::Worker.max_attempts = 25
102
+ describe "failed jobs" do
103
+ before do
104
+ # reset defaults
105
+ Delayed::Worker.destroy_failed_jobs = true
106
+ Delayed::Worker.max_attempts = 25
111
107
 
112
- @job = Delayed::Job.enqueue ErrorJob.new
113
- end
108
+ @job = Delayed::Job.enqueue ErrorJob.new
109
+ end
114
110
 
115
- it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
116
- Delayed::Worker.destroy_failed_jobs = false
117
- Delayed::Worker.max_attempts = 1
118
- @worker.run(@job)
119
- @job.reload
120
- @job.last_error.should =~ /did not work/
121
- @job.last_error.should =~ /worker_spec.rb/
122
- @job.attempts.should == 1
123
- @job.failed_at.should_not be_nil
124
- end
111
+ it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
112
+ Delayed::Worker.destroy_failed_jobs = false
113
+ Delayed::Worker.max_attempts = 1
114
+ @worker.run(@job)
115
+ @job.reload
116
+ @job.last_error.should =~ /did not work/
117
+ @job.last_error.should =~ /worker_spec.rb/
118
+ @job.attempts.should == 1
119
+ @job.failed_at.should_not be_nil
120
+ end
125
121
 
126
- it "should re-schedule jobs after failing" do
127
- @worker.run(@job)
128
- @job.reload
129
- @job.last_error.should =~ /did not work/
130
- @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
131
- @job.attempts.should == 1
132
- @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
133
- @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
134
- end
135
- end
122
+ it "should re-schedule jobs after failing" do
123
+ @worker.run(@job)
124
+ @job.reload
125
+ @job.last_error.should =~ /did not work/
126
+ @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
127
+ @job.attempts.should == 1
128
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
129
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
130
+ end
131
+ end
136
132
 
137
- context "reschedule" do
138
- before do
139
- @job = Delayed::Job.create :payload_object => SimpleJob.new
140
- end
133
+ context "reschedule" do
134
+ before do
135
+ @job = Delayed::Job.create :payload_object => SimpleJob.new
136
+ end
141
137
 
142
- context "and we want to destroy jobs" do
143
- before do
144
- Delayed::Worker.destroy_failed_jobs = true
145
- end
138
+ context "and we want to destroy jobs" do
139
+ before do
140
+ Delayed::Worker.destroy_failed_jobs = true
141
+ end
146
142
 
147
- it "should be destroyed if it failed more than Worker.max_attempts times" do
148
- @job.should_receive(:destroy)
149
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
150
- end
143
+ it "should be destroyed if it failed more than Worker.max_attempts times" do
144
+ @job.should_receive(:destroy)
145
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
146
+ end
151
147
 
152
- it "should not be destroyed if failed fewer than Worker.max_attempts times" do
153
- @job.should_not_receive(:destroy)
154
- (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
155
- end
156
- end
148
+ it "should not be destroyed if failed fewer than Worker.max_attempts times" do
149
+ @job.should_not_receive(:destroy)
150
+ (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
151
+ end
152
+ end
157
153
 
158
- context "and we don't want to destroy jobs" do
159
- before do
160
- Delayed::Worker.destroy_failed_jobs = false
161
- end
154
+ context "and we don't want to destroy jobs" do
155
+ before do
156
+ Delayed::Worker.destroy_failed_jobs = false
157
+ end
162
158
 
163
- it "should be failed if it failed more than Worker.max_attempts times" do
164
- @job.reload.failed_at.should == nil
165
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
166
- @job.reload.failed_at.should_not == nil
167
- end
159
+ it "should be failed if it failed more than Worker.max_attempts times" do
160
+ @job.reload.failed_at.should == nil
161
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
162
+ @job.reload.failed_at.should_not == nil
163
+ end
168
164
 
169
- it "should not be failed if it failed fewer than Worker.max_attempts times" do
170
- (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
171
- @job.reload.failed_at.should == nil
172
- end
165
+ it "should not be failed if it failed fewer than Worker.max_attempts times" do
166
+ (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
167
+ @job.reload.failed_at.should == nil
168
+ end
173
169
 
170
+ end
171
+ end
174
172
  end
175
173
  end
176
174
 
177
-
178
175
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0pre
4
+ prerelease: false
5
+ segments:
6
+ - 2
7
+ - 0
8
+ - 0
9
+ version: 2.0.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Brandon Keepers
@@ -10,39 +15,117 @@ autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
17
 
13
- date: 2010-03-26 00:00:00 -04:00
18
+ date: 2010-04-03 00:00:00 -04:00
14
19
  default_executable:
15
20
  dependencies:
16
21
  - !ruby/object:Gem::Dependency
17
22
  name: daemons
18
- type: :runtime
19
- version_requirement:
20
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
21
25
  requirements:
22
26
  - - ">="
23
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
24
30
  version: "0"
25
- version:
31
+ type: :runtime
32
+ version_requirements: *id001
26
33
  - !ruby/object:Gem::Dependency
27
34
  name: rspec
28
- type: :development
29
- version_requirement:
30
- version_requirements: !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
31
37
  requirements:
32
38
  - - ">="
33
39
  - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
34
42
  version: "0"
35
- version:
43
+ type: :development
44
+ version_requirements: *id002
36
45
  - !ruby/object:Gem::Dependency
37
46
  name: sqlite3-ruby
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ type: :development
56
+ version_requirements: *id003
57
+ - !ruby/object:Gem::Dependency
58
+ name: mongo_mapper
59
+ prerelease: false
60
+ requirement: &id004 !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ type: :development
68
+ version_requirements: *id004
69
+ - !ruby/object:Gem::Dependency
70
+ name: dm-core
71
+ prerelease: false
72
+ requirement: &id005 !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
38
79
  type: :development
39
- version_requirement:
40
- version_requirements: !ruby/object:Gem::Requirement
80
+ version_requirements: *id005
81
+ - !ruby/object:Gem::Dependency
82
+ name: dm-observer
83
+ prerelease: false
84
+ requirement: &id006 !ruby/object:Gem::Requirement
41
85
  requirements:
42
86
  - - ">="
43
87
  - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
44
90
  version: "0"
45
- version:
91
+ type: :development
92
+ version_requirements: *id006
93
+ - !ruby/object:Gem::Dependency
94
+ name: dm-aggregates
95
+ prerelease: false
96
+ requirement: &id007 !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ type: :development
104
+ version_requirements: *id007
105
+ - !ruby/object:Gem::Dependency
106
+ name: do_sqlite3
107
+ prerelease: false
108
+ requirement: &id008 !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ type: :development
116
+ version_requirements: *id008
117
+ - !ruby/object:Gem::Dependency
118
+ name: database_cleaner
119
+ prerelease: false
120
+ requirement: &id009 !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ type: :development
128
+ version_requirements: *id009
46
129
  description: |-
47
130
  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.
48
131
 
@@ -60,6 +143,7 @@ files:
60
143
  - README.textile
61
144
  - Rakefile
62
145
  - VERSION
146
+ - benchmarks.rb
63
147
  - contrib/delayed_job.monitrc
64
148
  - delayed_job.gemspec
65
149
  - generators/delayed_job/delayed_job_generator.rb
@@ -67,6 +151,7 @@ files:
67
151
  - generators/delayed_job/templates/script
68
152
  - lib/delayed/backend/active_record.rb
69
153
  - lib/delayed/backend/base.rb
154
+ - lib/delayed/backend/data_mapper.rb
70
155
  - lib/delayed/backend/mongo_mapper.rb
71
156
  - lib/delayed/command.rb
72
157
  - lib/delayed/message_sending.rb
@@ -78,12 +163,14 @@ files:
78
163
  - rails/init.rb
79
164
  - recipes/delayed_job.rb
80
165
  - spec/backend/active_record_job_spec.rb
166
+ - spec/backend/data_mapper_job_spec.rb
81
167
  - spec/backend/mongo_mapper_job_spec.rb
82
168
  - spec/backend/shared_backend_spec.rb
83
169
  - spec/delayed_method_spec.rb
84
170
  - spec/performable_method_spec.rb
85
171
  - spec/sample_jobs.rb
86
172
  - spec/setup/active_record.rb
173
+ - spec/setup/data_mapper.rb
87
174
  - spec/setup/mongo_mapper.rb
88
175
  - spec/spec_helper.rb
89
176
  - spec/story_spec.rb
@@ -105,30 +192,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
192
  requirements:
106
193
  - - ">="
107
194
  - !ruby/object:Gem::Version
195
+ segments:
196
+ - 0
108
197
  version: "0"
109
- version:
110
198
  required_rubygems_version: !ruby/object:Gem::Requirement
111
199
  requirements:
112
200
  - - ">="
113
201
  - !ruby/object:Gem::Version
202
+ segments:
203
+ - 0
114
204
  version: "0"
115
- version:
116
205
  requirements: []
117
206
 
118
207
  rubyforge_project:
119
- rubygems_version: 1.3.5
208
+ rubygems_version: 1.3.6
120
209
  signing_key:
121
210
  specification_version: 3
122
211
  summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
123
212
  test_files:
124
- - spec/backend/active_record_job_spec.rb
125
- - spec/backend/mongo_mapper_job_spec.rb
126
- - spec/backend/shared_backend_spec.rb
127
213
  - spec/delayed_method_spec.rb
128
214
  - spec/performable_method_spec.rb
129
- - spec/sample_jobs.rb
130
- - spec/setup/active_record.rb
131
- - spec/setup/mongo_mapper.rb
132
- - spec/spec_helper.rb
133
215
  - spec/story_spec.rb
134
216
  - spec/worker_spec.rb