delayed_job 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,4 +1,4 @@
1
- h1. Delayed::Job
1
+ h1. Delayed::Job "!http://travis-ci.org/collectiveidea/delayed_job.png!":http://travis-ci.org/collectiveidea/delayed_job "!https://gemnasium.com/collectiveidea/delayed_job.png?travis!":https://gemnasium.com/collectiveidea/delayed_job
2
2
 
3
3
  Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
4
4
 
@@ -18,6 +18,8 @@ h2. Installation
18
18
 
19
19
  delayed_job 3.0.0 only supports Rails 3.0+. See the "2.0 branch":https://github.com/collectiveidea/delayed_job/tree/v2.0 for Rails 2.
20
20
 
21
+ delayed_job supports multiple backends for storing the job queue. "See the wiki for other backends":http://wiki.github.com/collectiveidea/delayed_job/backends.
22
+
21
23
  If you plan to use delayed_job with Active Record, add @delayed_job_active_record@ to your @Gemfile@.
22
24
 
23
25
  <pre>
@@ -32,11 +34,7 @@ gem 'delayed_job_mongoid'
32
34
 
33
35
  Run @bundle install@ to install the backend and delayed_job gems.
34
36
 
35
- h3. Backends
36
-
37
- delayed_job supports multiple backends for storing the job queue. "See the wiki for other backends":http://wiki.github.com/collectiveidea/delayed_job/backends besides Active Record.
38
-
39
- The default is Active Record, which requires a jobs table. You can create that table by running the following command:
37
+ The Active Record backend requires a jobs table. You can create that table by running the following command:
40
38
 
41
39
  <pre>
42
40
  $ script/rails generate delayed_job:active_record
@@ -80,7 +78,7 @@ device = Device.new
80
78
  device.deliver
81
79
  </pre>
82
80
 
83
- handle_asynchronously can take as options anything you can pass to delay. In addition the values can be Proc objects allowing call time evaluation of the value. For some examples:
81
+ handle_asynchronously can take as options anything you can pass to delay. In addition, the values can be Proc objects allowing call time evaluation of the value. For some examples:
84
82
 
85
83
  <pre>
86
84
  class LongTasks
@@ -127,6 +125,19 @@ Notifier.delay.signup(@user)
127
125
 
128
126
  Remove the @.deliver@ method to make it work. It's not ideal, but it's the best we could do for now.
129
127
 
128
+ h3. Named Queues
129
+
130
+ DJ 3 introduces Resque-style named queues while still retaining DJ-style priority. The goal is to provide a system for grouping tasks to be worked by separate pools of workers, which may be scaled and controlled individually.
131
+
132
+ Jobs can be assigned to a queue by setting the @queue@ option:
133
+
134
+ <pre>object.delay(:queue => 'tracking').method
135
+
136
+ Delayed::Job.enqueue job, :queue => 'tracking'
137
+
138
+ handle_asynchronously :tweet_later, :queue => 'tweets'
139
+ </pre>
140
+
130
141
  h2. Running Jobs
131
142
 
132
143
  @script/delayed_job@ can be used to manage a background process which will start working off jobs.
@@ -142,12 +153,23 @@ $ RAILS_ENV=production script/delayed_job stop
142
153
  # Runs two workers in separate processes.
143
154
  $ RAILS_ENV=production script/delayed_job -n 2 start
144
155
  $ RAILS_ENV=production script/delayed_job stop
156
+
157
+ # Set the --queue or --queues option to work from a particular queue.
158
+ $ RAILS_ENV=production script/delayed_job --queue=tracking start
159
+ $ RAILS_ENV=production script/delayed_job --queues=mailers,tasks start
145
160
  </pre>
146
161
 
147
162
  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.
148
163
 
149
164
  You can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@.
150
165
 
166
+ Work off queues by setting the @QUEUE@ or @QUEUES@ environment variable.
167
+
168
+ <pre>
169
+ QUEUE=tracking rake jobs:work
170
+ QUEUES=mailers,tasks rake jobs:work
171
+ </pre>
172
+
151
173
  h2. Custom Jobs
152
174
 
153
175
  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.
@@ -251,14 +273,6 @@ h2. Mailing List
251
273
 
252
274
  Join us on the "mailing list":http://groups.google.com/group/delayed_job
253
275
 
254
- h2. Build Status
255
-
256
- "!http://travis-ci.org/collectiveidea/delayed_job.png!":http://travis-ci.org/collectiveidea/delayed_job
257
-
258
- h2. Dependency Status
259
-
260
- "!https://gemnasium.com/collectiveidea/delayed_job.png?travis!":https://gemnasium.com/collectiveidea/delayed_job
261
-
262
276
  h2. How to contribute
263
277
 
264
278
  If you find what looks like a bug:
@@ -237,8 +237,8 @@ shared_examples_for 'a delayed_job backend' do
237
237
  end
238
238
 
239
239
  it "should be the instance method that will be called if its a performable method object" do
240
- @job = Story.create(:text => "...").delay.save
241
- @job.name.should == 'Story#save'
240
+ job = Story.create(:text => "...").delay.save
241
+ job.name.should == 'Story#save'
242
242
  end
243
243
 
244
244
  it "should parse from handler on deserialization error" do
@@ -415,10 +415,10 @@ shared_examples_for 'a delayed_job backend' do
415
415
  begin
416
416
  old_max_run_time = Delayed::Worker.max_run_time
417
417
  Delayed::Worker.max_run_time = 1.second
418
- @job = Delayed::Job.create :payload_object => LongRunningJob.new
419
- worker.run(@job)
420
- @job.reload.last_error.should =~ /expired/
421
- @job.attempts.should == 1
418
+ job = Delayed::Job.create :payload_object => LongRunningJob.new
419
+ worker.run(job)
420
+ job.reload.last_error.should =~ /expired/
421
+ job.attempts.should == 1
422
422
  ensure
423
423
  Delayed::Worker.max_run_time = old_max_run_time
424
424
  end
@@ -467,11 +467,11 @@ shared_examples_for 'a delayed_job backend' do
467
467
  end
468
468
 
469
469
  it 'should re-schedule with handler provided time if present' do
470
- @job = Delayed::Job.enqueue(CustomRescheduleJob.new(99.minutes))
471
- worker.run(@job)
472
- @job.reload
470
+ job = Delayed::Job.enqueue(CustomRescheduleJob.new(99.minutes))
471
+ worker.run(job)
472
+ job.reload
473
473
 
474
- (Delayed::Job.db_time_now + 99.minutes - @job.run_at).abs.should < 1
474
+ (Delayed::Job.db_time_now + 99.minutes - job.run_at).abs.should < 1
475
475
  end
476
476
 
477
477
  it "should not fail when the triggered error doesn't have a message" do
@@ -23,19 +23,77 @@ module Psych
23
23
  module Visitors
24
24
  class YAMLTree
25
25
  def visit_Class(klass)
26
- tag = ['!ruby/class', klass.name].join(':')
27
- register(klass, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK))
28
- @emitter.end_mapping
26
+ @emitter.scalar klass.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED
29
27
  end
30
28
  end
31
29
 
32
30
  class ToRuby
31
+ def visit_Psych_Nodes_Scalar(o)
32
+ @st[o.anchor] = o.value if o.anchor
33
+
34
+ if klass = Psych.load_tags[o.tag]
35
+ instance = klass.allocate
36
+
37
+ if instance.respond_to?(:init_with)
38
+ coder = Psych::Coder.new(o.tag)
39
+ coder.scalar = o.value
40
+ instance.init_with coder
41
+ end
42
+
43
+ return instance
44
+ end
45
+
46
+ return o.value if o.quoted
47
+ return @ss.tokenize(o.value) unless o.tag
48
+
49
+ case o.tag
50
+ when '!binary', 'tag:yaml.org,2002:binary'
51
+ o.value.unpack('m').first
52
+ when '!str', 'tag:yaml.org,2002:str'
53
+ o.value
54
+ when "!ruby/object:DateTime"
55
+ require 'date'
56
+ @ss.parse_time(o.value).to_datetime
57
+ when "!ruby/object:Complex"
58
+ Complex(o.value)
59
+ when "!ruby/object:Rational"
60
+ Rational(o.value)
61
+ when "!ruby/class", "!ruby/module"
62
+ resolve_class o.value
63
+ when "tag:yaml.org,2002:float", "!float"
64
+ Float(@ss.tokenize(o.value))
65
+ when "!ruby/regexp"
66
+ o.value =~ /^\/(.*)\/([mixn]*)$/
67
+ source = $1
68
+ options = 0
69
+ lang = nil
70
+ ($2 || '').split('').each do |option|
71
+ case option
72
+ when 'x' then options |= Regexp::EXTENDED
73
+ when 'i' then options |= Regexp::IGNORECASE
74
+ when 'm' then options |= Regexp::MULTILINE
75
+ when 'n' then options |= Regexp::NOENCODING
76
+ else lang = option
77
+ end
78
+ end
79
+ Regexp.new(*[source, options, lang].compact)
80
+ when "!ruby/range"
81
+ args = o.value.split(/([.]{2,3})/, 2).map { |s|
82
+ accept Nodes::Scalar.new(s)
83
+ }
84
+ args.push(args.delete_at(1) == '...')
85
+ Range.new(*args)
86
+ when /^!ruby\/sym(bol)?:?(.*)?$/
87
+ o.value.to_sym
88
+ else
89
+ @ss.tokenize o.value
90
+ end
91
+ end
92
+
33
93
  def visit_Psych_Nodes_Mapping_with_class(object)
34
94
  return revive(Psych.load_tags[object.tag], object) if Psych.load_tags[object.tag]
35
95
 
36
96
  case object.tag
37
- when /^!ruby\/class:?(.*)?$/
38
- resolve_class $1
39
97
  when /^!ruby\/ActiveRecord:(.+)$/
40
98
  klass = resolve_class($1)
41
99
  payload = Hash[*object.children.map { |c| accept c }]
@@ -72,4 +130,3 @@ module Psych
72
130
  end
73
131
  end
74
132
  end
75
-
@@ -9,7 +9,7 @@ if defined?(ActiveRecord)
9
9
  klass.with_exclusive_scope { klass.find(val['attributes'][klass.primary_key]) }
10
10
  end
11
11
  rescue ActiveRecord::RecordNotFound
12
- raise Delayed::DeserializationError
12
+ raise Delayed::DeserializationError, "ActiveRecord::RecordNotFound, class: #{klass} , primary key: #{val['attributes'][klass.primary_key]} "
13
13
  end
14
14
 
15
15
  def to_yaml_properties
@@ -2,7 +2,7 @@ class Module
2
2
  yaml_as "tag:ruby.yaml.org,2002:module"
3
3
 
4
4
  def self.yaml_new(klass, tag, val)
5
- klass
5
+ val.constantize
6
6
  end
7
7
 
8
8
  def to_yaml(options = {})
@@ -2,7 +2,7 @@
2
2
  # Classes, Modules and Structs
3
3
 
4
4
  require 'yaml'
5
- if YAML.parser.class.name =~ /syck/i
5
+ if YAML.parser.class.name =~ /syck|yecht/i
6
6
  require File.expand_path('../syck_ext', __FILE__)
7
7
  require File.expand_path('../serialization/active_record', __FILE__)
8
8
  else
@@ -64,44 +64,4 @@ describe Delayed::Lifecycle do
64
64
  lifecycle.before(:execute, &callback)
65
65
  expect { lifecycle.run_callbacks(:execute, 1,2,3) {} }.to raise_error(ArgumentError, /1 parameter/)
66
66
  end
67
-
68
- # # This is a spectacularly crappy way to test callbacks. What's a better way?
69
- # describe 'arguments callbacks' do
70
- # subject do
71
- # class Testarguments < Delayed::arguments
72
- # def before_execute; end
73
- # def before_loop; end
74
- # def before_perform; end
75
- #
76
- # set_callback :execute, :before, :before_execute
77
- # set_callback :loop, :before, :before_loop
78
- # set_callback :perform, :before, :before_perform
79
- # end
80
- #
81
- # Testarguments.new.tap { |w| w.stop }
82
- # end
83
- #
84
- # it "should trigger for execute event" do
85
- # subject.should_receive(:before_execute).with()
86
- # subject.start
87
- # end
88
- #
89
- # it "should trigger for loop event" do
90
- # subject.should_receive(:before_loop).with()
91
- # subject.start
92
- # end
93
- #
94
- # it "should trigger for perform event" do
95
- # "foo".delay.length
96
- # subject.should_receive(:before_perform).with()
97
- # subject.start
98
- # end
99
- # end
100
- #
101
- # describe 'job callbacks' do
102
- # it "should trigger for enqueue event" do
103
- # pending 'figure out how to test this'
104
- # end
105
- # end
106
-
107
67
  end
@@ -3,8 +3,7 @@ require 'spec_helper'
3
3
  describe Delayed::MessageSending do
4
4
  describe "handle_asynchronously" do
5
5
  class Story
6
- def tell!(arg)
7
- end
6
+ def tell!(arg);end
8
7
  handle_asynchronously :tell!
9
8
  end
10
9
 
@@ -17,19 +16,16 @@ describe Delayed::MessageSending do
17
16
  story = Story.new
18
17
  lambda {
19
18
  job = story.tell!(1)
20
- job.payload_object.class.should == Delayed::PerformableMethod
21
- job.payload_object.method_name.should == :tell_without_delay!
22
- job.payload_object.args.should == [1]
19
+ job.payload_object.class.should == Delayed::PerformableMethod
20
+ job.payload_object.method_name.should == :tell_without_delay!
21
+ job.payload_object.args.should == [1]
23
22
  }.should change { Delayed::Job.count }
24
23
  end
25
24
 
26
25
  describe 'with options' do
27
26
  class Fable
28
- class << self
29
- attr_accessor :importance
30
- end
31
- def tell
32
- end
27
+ cattr_accessor :importance
28
+ def tell;end
33
29
  handle_asynchronously :tell, :priority => Proc.new { self.importance }
34
30
  end
35
31
 
@@ -43,7 +39,7 @@ describe Delayed::MessageSending do
43
39
  job.priority.should == 20
44
40
  end
45
41
 
46
- describe 'using a proc with parament' do
42
+ describe 'using a proc with parameters' do
47
43
  class Yarn
48
44
  attr_accessor :importance
49
45
  def spin
@@ -63,36 +59,37 @@ describe Delayed::MessageSending do
63
59
  end
64
60
 
65
61
  context "delay" do
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
+
66
70
  it "should create a new PerformableMethod job" do
67
71
  lambda {
68
72
  job = "hello".delay.count('l')
69
- job.payload_object.class.should == Delayed::PerformableMethod
70
- job.payload_object.method_name.should == :count
71
- job.payload_object.args.should == ['l']
73
+ job.payload_object.class.should == Delayed::PerformableMethod
74
+ job.payload_object.method_name.should == :count
75
+ job.payload_object.args.should == ['l']
72
76
  }.should change { Delayed::Job.count }.by(1)
73
77
  end
74
78
 
75
79
  it "should set default priority" do
76
80
  Delayed::Worker.default_priority = 99
77
- job = Object.delay.to_s
81
+ job = FairyTail.delay.to_s
78
82
  job.priority.should == 99
79
83
  Delayed::Worker.default_priority = 0
80
84
  end
81
85
 
82
86
  it "should set job options" do
83
87
  run_at = Time.parse('2010-05-03 12:55 AM')
84
- job = Object.delay(:priority => 20, :run_at => run_at).to_s
88
+ job = FairyTail.delay(:priority => 20, :run_at => run_at).to_s
85
89
  job.run_at.should == run_at
86
90
  job.priority.should == 20
87
91
  end
88
92
 
89
- class FairyTail
90
- attr_accessor :happy_ending
91
- def tell
92
- @happy_ending = true
93
- end
94
- end
95
-
96
93
  it "should not delay the job when delay_jobs is false" do
97
94
  Delayed::Worker.delay_jobs = false
98
95
  fairy_tail = FairyTail.new
@@ -12,9 +12,9 @@ describe ActionMailer::Base do
12
12
  it "should enqueue a PerformableEmail job" do
13
13
  lambda {
14
14
  job = MyMailer.delay.signup('john@example.com')
15
- job.payload_object.class.should == Delayed::PerformableMailer
16
- job.payload_object.method_name.should == :signup
17
- job.payload_object.args.should == ['john@example.com']
15
+ job.payload_object.class.should == Delayed::PerformableMailer
16
+ job.payload_object.method_name.should == :signup
17
+ job.payload_object.args.should == ['john@example.com']
18
18
  }.should change { Delayed::Job.count }.by(1)
19
19
  end
20
20
  end
@@ -29,16 +29,14 @@ describe ActionMailer::Base do
29
29
 
30
30
  describe Delayed::PerformableMailer do
31
31
  describe "perform" do
32
- before do
33
- @email = mock('email', :deliver => true)
34
- @mailer_class = mock('MailerClass', :signup => @email)
35
- @mailer = Delayed::PerformableMailer.new(@mailer_class, :signup, ['john@example.com'])
36
- end
37
-
38
32
  it "should call the method and #deliver on the mailer" do
39
- @mailer_class.should_receive(:signup).with('john@example.com')
40
- @email.should_receive(:deliver)
41
- @mailer.perform
33
+ email = mock('email', :deliver => true)
34
+ mailer_class = mock('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
42
40
  end
43
41
  end
44
42
  end
@@ -3,14 +3,14 @@ require 'spec_helper'
3
3
  describe "YAML" do
4
4
  it "should autoload classes" do
5
5
  lambda {
6
- yaml = "--- !ruby/class:Autoloaded::Clazz {}\n"
6
+ yaml = "--- !ruby/class Autoloaded::Clazz\n"
7
7
  YAML.load(yaml).should == Autoloaded::Clazz
8
8
  }.should_not raise_error
9
9
  end
10
10
 
11
11
  it "should autoload the class of a struct" do
12
12
  lambda {
13
- yaml = "--- !ruby/class:Autoloaded::Struct {}\n"
13
+ yaml = "--- !ruby/class Autoloaded::Struct\n"
14
14
  YAML.load(yaml).should == Autoloaded::Struct
15
15
  }.should_not raise_error
16
16
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 0
10
- version: 3.0.0
9
+ - 1
10
+ version: 3.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Griffin
@@ -20,7 +20,7 @@ autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
22
 
23
- date: 2011-12-30 00:00:00 Z
23
+ date: 2012-01-24 00:00:00 Z
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
26
26
  version_requirements: &id001 !ruby/object:Gem::Requirement