delayed_job 1.9.0pre → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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