que 0.0.1 → 0.1.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.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/README.md +85 -44
- data/Rakefile +412 -0
- data/lib/generators/que/install_generator.rb +22 -0
- data/lib/generators/que/templates/add_que.rb +9 -0
- data/lib/que.rb +55 -5
- data/lib/que/adapters/active_record.rb +9 -0
- data/lib/que/adapters/base.rb +49 -0
- data/lib/que/adapters/connection_pool.rb +14 -0
- data/lib/que/adapters/pg.rb +17 -0
- data/lib/que/adapters/sequel.rb +14 -0
- data/lib/que/job.rb +128 -149
- data/lib/que/railtie.rb +20 -0
- data/lib/que/rake_tasks.rb +35 -0
- data/lib/que/sql.rb +121 -0
- data/lib/que/version.rb +1 -1
- data/lib/que/worker.rb +93 -156
- data/que.gemspec +8 -6
- data/spec/adapters/active_record_spec.rb +39 -0
- data/spec/adapters/connection_pool_spec.rb +12 -0
- data/spec/adapters/pg_spec.rb +5 -0
- data/spec/adapters/sequel_spec.rb +25 -0
- data/spec/connection_spec.rb +12 -0
- data/spec/helper_spec.rb +19 -0
- data/spec/pool_spec.rb +116 -0
- data/spec/queue_spec.rb +134 -0
- data/spec/spec_helper.rb +48 -25
- data/spec/support/helpers.rb +9 -0
- data/spec/support/jobs.rb +33 -0
- data/spec/support/shared_examples/adapter.rb +16 -0
- data/spec/support/shared_examples/multithreaded_adapter.rb +42 -0
- data/spec/work_spec.rb +247 -0
- data/spec/worker_spec.rb +117 -0
- metadata +73 -15
- data/spec/unit/error_spec.rb +0 -45
- data/spec/unit/queue_spec.rb +0 -67
- data/spec/unit/work_spec.rb +0 -168
- data/spec/unit/worker_spec.rb +0 -31
data/que.gemspec
CHANGED
@@ -5,12 +5,12 @@ require 'que/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'que'
|
8
|
-
spec.version = Que::
|
8
|
+
spec.version = Que::Version
|
9
9
|
spec.authors = ["Chris Hanks"]
|
10
10
|
spec.email = ['christopher.m.hanks@gmail.com']
|
11
|
-
spec.description = %q{
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.homepage = ''
|
11
|
+
spec.description = %q{A job queue that uses PostgreSQL's advisory locks for speed and reliability.}
|
12
|
+
spec.summary = %q{A PostgreSQL-based Job Queue}
|
13
|
+
spec.homepage = 'https://github.com/chanks/que'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'rspec', '~> 2.14.1'
|
24
24
|
spec.add_development_dependency 'pry'
|
25
25
|
|
26
|
-
spec.
|
27
|
-
spec.
|
26
|
+
spec.add_development_dependency 'sequel'
|
27
|
+
spec.add_development_dependency 'activerecord'
|
28
|
+
spec.add_development_dependency 'pg'
|
29
|
+
spec.add_development_dependency 'connection_pool'
|
28
30
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
ActiveRecord::Base.establish_connection(QUE_URL)
|
5
|
+
Que.connection = ActiveRecord
|
6
|
+
QUE_ADAPTERS[:active_record] = Que.adapter
|
7
|
+
|
8
|
+
describe "Que using the ActiveRecord adapter" do
|
9
|
+
before { Que.adapter = QUE_ADAPTERS[:active_record] }
|
10
|
+
|
11
|
+
it_behaves_like "a Que adapter"
|
12
|
+
it_behaves_like "a multithreaded Que adapter"
|
13
|
+
|
14
|
+
it "should use the same connection that ActiveRecord does" do
|
15
|
+
class ActiveRecordJob < Que::Job
|
16
|
+
def run
|
17
|
+
$pid1 = Que.execute("SELECT pg_backend_pid()").first['pg_backend_pid'].to_i
|
18
|
+
$pid2 = ActiveRecord::Base.connection.select_all("select pg_backend_pid()").rows.first.first.to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
ActiveRecordJob.queue
|
23
|
+
Que::Job.work
|
24
|
+
|
25
|
+
$pid1.should == $pid2
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should instantiate args as ActiveSupport::HashWithIndifferentAccess" do
|
29
|
+
ArgsJob.queue :param => 2
|
30
|
+
Que::Job.work
|
31
|
+
$passed_args.first[:param].should == 2
|
32
|
+
$passed_args.first.should be_an_instance_of ActiveSupport::HashWithIndifferentAccess
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should support Rails' special extensions for times" do
|
36
|
+
Que::Job.queue :run_at => 1.minute.from_now
|
37
|
+
DB[:que_jobs].get(:run_at).should be_within(3).of Time.now + 60
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'connection_pool'
|
3
|
+
|
4
|
+
Que.connection = ConnectionPool.new &NEW_PG_CONNECTION
|
5
|
+
QUE_ADAPTERS[:connection_pool] = Que.adapter
|
6
|
+
|
7
|
+
describe "Que using the ConnectionPool adapter" do
|
8
|
+
before { Que.adapter = QUE_ADAPTERS[:connection_pool] }
|
9
|
+
|
10
|
+
it_behaves_like "a Que adapter"
|
11
|
+
it_behaves_like "a multithreaded Que adapter"
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
Que.connection = SEQUEL_ADAPTER_DB = Sequel.connect(QUE_URL)
|
4
|
+
QUE_ADAPTERS[:sequel] = Que.adapter
|
5
|
+
|
6
|
+
describe "Que using the Sequel adapter" do
|
7
|
+
before { Que.adapter = QUE_ADAPTERS[:sequel] }
|
8
|
+
|
9
|
+
it_behaves_like "a Que adapter"
|
10
|
+
it_behaves_like "a multithreaded Que adapter"
|
11
|
+
|
12
|
+
it "should use the same connection that Sequel does" do
|
13
|
+
class SequelJob < Que::Job
|
14
|
+
def run
|
15
|
+
$pid1 = Que.execute("SELECT pg_backend_pid()").first['pg_backend_pid'].to_i
|
16
|
+
$pid2 = SEQUEL_ADAPTER_DB.get{pg_backend_pid{}}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
SequelJob.queue
|
21
|
+
Que::Job.work
|
22
|
+
|
23
|
+
$pid1.should == $pid2
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Que do
|
4
|
+
it ".connection= with an unsupported connection should raise an error" do
|
5
|
+
proc{Que.connection = "ferret"}.should raise_error RuntimeError, /Que connection not recognized: "ferret"/
|
6
|
+
end
|
7
|
+
|
8
|
+
it ".adapter when no connection has been established should raise an error" do
|
9
|
+
Que.connection = nil
|
10
|
+
proc{Que.adapter}.should raise_error RuntimeError, /Que connection not established!/
|
11
|
+
end
|
12
|
+
end
|
data/spec/helper_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Que, 'helpers' do
|
4
|
+
it "should be able to drop and create the jobs table" do
|
5
|
+
DB.table_exists?(:que_jobs).should be true
|
6
|
+
Que.drop!
|
7
|
+
DB.table_exists?(:que_jobs).should be false
|
8
|
+
Que.execute "SET client_min_messages TO 'warning'" # Avoid annoying NOTICE messages.
|
9
|
+
Que.create!
|
10
|
+
DB.table_exists?(:que_jobs).should be true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be able to clear the jobs table" do
|
14
|
+
DB[:que_jobs].insert :job_class => "Que::Job"
|
15
|
+
DB[:que_jobs].count.should be 1
|
16
|
+
Que.clear!
|
17
|
+
DB[:que_jobs].count.should be 0
|
18
|
+
end
|
19
|
+
end
|
data/spec/pool_spec.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Managing the Worker pool" do
|
4
|
+
it "should log mode changes" do
|
5
|
+
Que.mode = :off
|
6
|
+
$logger.messages.should == ["[Que] Set mode to :off"]
|
7
|
+
end
|
8
|
+
|
9
|
+
it "Que.mode = :sync should make jobs run in the same thread as they are queued" do
|
10
|
+
Que.mode = :sync
|
11
|
+
|
12
|
+
ArgsJob.queue(5, :testing => "synchronous").should be_an_instance_of ArgsJob
|
13
|
+
$passed_args.should == [5, {'testing' => "synchronous"}]
|
14
|
+
DB[:que_jobs].count.should be 0
|
15
|
+
|
16
|
+
$logger.messages.length.should be 2
|
17
|
+
$logger.messages[0].should == "[Que] Set mode to :sync"
|
18
|
+
$logger.messages[1].should =~ /\A\[Que\] Worked job in/
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "Que.mode = :async" do
|
22
|
+
it "should spin up 4 workers" do
|
23
|
+
Que.mode = :async
|
24
|
+
workers = Que::Worker.workers
|
25
|
+
workers.count.should be 4
|
26
|
+
sleep_until { workers.all?(&:sleeping?) }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "then Que.worker_count = 2 should gracefully decrease the number of workers" do
|
30
|
+
Que.mode = :async
|
31
|
+
workers = Que::Worker.workers.dup
|
32
|
+
workers.count.should be 4
|
33
|
+
|
34
|
+
Que.worker_count = 2
|
35
|
+
Que::Worker.workers.count.should be 2
|
36
|
+
sleep_until { Que::Worker.workers.all?(&:sleeping?) }
|
37
|
+
|
38
|
+
workers[0..1].should == Que::Worker.workers
|
39
|
+
workers[2..3].each do |worker|
|
40
|
+
worker.should be_an_instance_of Que::Worker
|
41
|
+
worker.thread.status.should == false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "then Que.worker_count = 6 should gracefully increase the number of workers" do
|
46
|
+
Que.mode = :async
|
47
|
+
workers = Que::Worker.workers.dup
|
48
|
+
workers.count.should be 4
|
49
|
+
|
50
|
+
Que.worker_count = 6
|
51
|
+
Que::Worker.workers.count.should be 6
|
52
|
+
sleep_until { workers.all?(&:sleeping?) }
|
53
|
+
|
54
|
+
workers.should == Que::Worker.workers[0..3]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "then Que.mode = :off should gracefully shut down workers" do
|
58
|
+
Que.mode = :async
|
59
|
+
workers = Que::Worker.workers.dup
|
60
|
+
workers.count.should be 4
|
61
|
+
|
62
|
+
Que.mode = :off
|
63
|
+
Que::Worker.workers.length.should be 0
|
64
|
+
|
65
|
+
workers.count.should be 4
|
66
|
+
workers.each { |worker| worker.thread.status.should be false }
|
67
|
+
end
|
68
|
+
|
69
|
+
it "then Que::Worker.wake! should wake up a single worker" do
|
70
|
+
Que.mode = :async
|
71
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
72
|
+
|
73
|
+
BlockJob.queue
|
74
|
+
Que::Worker.wake!
|
75
|
+
|
76
|
+
$q1.pop
|
77
|
+
Que::Worker.workers.first.should be_working
|
78
|
+
Que::Worker.workers[1..3].each { |w| w.should be_sleeping }
|
79
|
+
DB[:que_jobs].count.should be 1
|
80
|
+
$q2.push nil
|
81
|
+
|
82
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
83
|
+
DB[:que_jobs].count.should be 0
|
84
|
+
end
|
85
|
+
|
86
|
+
it "then Que::Worker.wake_all! should wake up all workers" do
|
87
|
+
# This spec requires at least four connections.
|
88
|
+
Que.adapter = QUE_ADAPTERS[:connection_pool]
|
89
|
+
|
90
|
+
Que.mode = :async
|
91
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
92
|
+
|
93
|
+
4.times { BlockJob.queue }
|
94
|
+
Que::Worker.wake_all!
|
95
|
+
4.times { $q1.pop }
|
96
|
+
|
97
|
+
Que::Worker.workers.each{ |worker| worker.should be_working }
|
98
|
+
4.times { $q2.push nil }
|
99
|
+
|
100
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
101
|
+
DB[:que_jobs].count.should be 0
|
102
|
+
end if QUE_ADAPTERS[:connection_pool]
|
103
|
+
|
104
|
+
it "should poke a worker every Que.sleep_period seconds" do
|
105
|
+
begin
|
106
|
+
Que.sleep_period = 0.001 # 1 ms
|
107
|
+
Que.mode = :async
|
108
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
109
|
+
Que::Job.queue
|
110
|
+
sleep_until { DB[:que_jobs].count == 0 }
|
111
|
+
ensure
|
112
|
+
Que.sleep_period = nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/queue_spec.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Que::Job, '.queue' do
|
4
|
+
it "should be able to queue a job" do
|
5
|
+
DB[:que_jobs].count.should be 0
|
6
|
+
Que::Job.queue
|
7
|
+
DB[:que_jobs].count.should be 1
|
8
|
+
|
9
|
+
job = DB[:que_jobs].first
|
10
|
+
job[:priority].should be 1
|
11
|
+
job[:run_at].should be_within(3).of Time.now
|
12
|
+
job[:job_class].should == "Que::Job"
|
13
|
+
JSON.load(job[:args]).should == []
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to queue a job with arguments" do
|
17
|
+
DB[:que_jobs].count.should be 0
|
18
|
+
Que::Job.queue 1, 'two'
|
19
|
+
DB[:que_jobs].count.should be 1
|
20
|
+
|
21
|
+
job = DB[:que_jobs].first
|
22
|
+
job[:priority].should be 1
|
23
|
+
job[:run_at].should be_within(3).of Time.now
|
24
|
+
job[:job_class].should == "Que::Job"
|
25
|
+
JSON.load(job[:args]).should == [1, 'two']
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to queue a job with complex arguments" do
|
29
|
+
DB[:que_jobs].count.should be 0
|
30
|
+
Que::Job.queue 1, 'two', :string => "string",
|
31
|
+
:integer => 5,
|
32
|
+
:array => [1, "two", {:three => 3}],
|
33
|
+
:hash => {:one => 1, :two => 'two', :three => [3]}
|
34
|
+
|
35
|
+
DB[:que_jobs].count.should be 1
|
36
|
+
|
37
|
+
job = DB[:que_jobs].first
|
38
|
+
job[:priority].should be 1
|
39
|
+
job[:run_at].should be_within(3).of Time.now
|
40
|
+
job[:job_class].should == "Que::Job"
|
41
|
+
JSON.load(job[:args]).should == [
|
42
|
+
1,
|
43
|
+
'two',
|
44
|
+
{
|
45
|
+
'string' => 'string',
|
46
|
+
'integer' => 5,
|
47
|
+
'array' => [1, "two", {"three" => 3}],
|
48
|
+
'hash' => {'one' => 1, 'two' => 'two', 'three' => [3]}
|
49
|
+
}
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should be able to queue a job with a specific time to run" do
|
54
|
+
DB[:que_jobs].count.should be 0
|
55
|
+
Que::Job.queue 1, :run_at => Time.now + 60
|
56
|
+
DB[:que_jobs].count.should be 1
|
57
|
+
|
58
|
+
job = DB[:que_jobs].first
|
59
|
+
job[:priority].should be 1
|
60
|
+
job[:run_at].should be_within(3).of Time.now + 60
|
61
|
+
job[:job_class].should == "Que::Job"
|
62
|
+
JSON.load(job[:args]).should == [1]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to queue a job with a specific priority" do
|
66
|
+
DB[:que_jobs].count.should be 0
|
67
|
+
Que::Job.queue 1, :priority => 4
|
68
|
+
DB[:que_jobs].count.should be 1
|
69
|
+
|
70
|
+
job = DB[:que_jobs].first
|
71
|
+
job[:priority].should be 4
|
72
|
+
job[:run_at].should be_within(3).of Time.now
|
73
|
+
job[:job_class].should == "Que::Job"
|
74
|
+
JSON.load(job[:args]).should == [1]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be able to queue a job with queueing options in addition to argument options" do
|
78
|
+
DB[:que_jobs].count.should be 0
|
79
|
+
Que::Job.queue 1, :string => "string", :run_at => Time.now + 60, :priority => 4
|
80
|
+
DB[:que_jobs].count.should be 1
|
81
|
+
|
82
|
+
job = DB[:que_jobs].first
|
83
|
+
job[:priority].should be 4
|
84
|
+
job[:run_at].should be_within(3).of Time.now + 60
|
85
|
+
job[:job_class].should == "Que::Job"
|
86
|
+
JSON.load(job[:args]).should == [1, {'string' => 'string'}]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should respect a default (but overridable) priority for the job class" do
|
90
|
+
class DefaultPriorityJob < Que::Job
|
91
|
+
@default_priority = 3
|
92
|
+
end
|
93
|
+
|
94
|
+
DB[:que_jobs].count.should be 0
|
95
|
+
DefaultPriorityJob.queue 1
|
96
|
+
DefaultPriorityJob.queue 1, :priority => 4
|
97
|
+
DB[:que_jobs].count.should be 2
|
98
|
+
|
99
|
+
first, second = DB[:que_jobs].order(:job_id).all
|
100
|
+
|
101
|
+
first[:priority].should be 3
|
102
|
+
first[:run_at].should be_within(3).of Time.now
|
103
|
+
first[:job_class].should == "DefaultPriorityJob"
|
104
|
+
JSON.load(first[:args]).should == [1]
|
105
|
+
|
106
|
+
second[:priority].should be 4
|
107
|
+
second[:run_at].should be_within(3).of Time.now
|
108
|
+
second[:job_class].should == "DefaultPriorityJob"
|
109
|
+
JSON.load(second[:args]).should == [1]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should respect a default (but overridable) run_at for the job class" do
|
113
|
+
class DefaultRunAtJob < Que::Job
|
114
|
+
@default_run_at = -> { Time.now + 60 }
|
115
|
+
end
|
116
|
+
|
117
|
+
DB[:que_jobs].count.should be 0
|
118
|
+
DefaultRunAtJob.queue 1
|
119
|
+
DefaultRunAtJob.queue 1, :run_at => Time.now + 30
|
120
|
+
DB[:que_jobs].count.should be 2
|
121
|
+
|
122
|
+
first, second = DB[:que_jobs].order(:job_id).all
|
123
|
+
|
124
|
+
first[:priority].should be 1
|
125
|
+
first[:run_at].should be_within(3).of Time.now + 60
|
126
|
+
first[:job_class].should == "DefaultRunAtJob"
|
127
|
+
JSON.load(first[:args]).should == [1]
|
128
|
+
|
129
|
+
second[:priority].should be 1
|
130
|
+
second[:run_at].should be_within(3).of Time.now + 30
|
131
|
+
second[:job_class].should == "DefaultRunAtJob"
|
132
|
+
JSON.load(second[:args]).should == [1]
|
133
|
+
end
|
134
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,34 +1,57 @@
|
|
1
|
-
require 'sequel'
|
2
1
|
require 'que'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
Dir["./spec/support/**/*.rb"].sort.each &method(:require)
|
4
|
+
|
5
|
+
QUE_URL = ENV["DATABASE_URL"] || "postgres://postgres:@localhost/que-test"
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
# Handy proc to instantiate new PG connections:
|
10
|
+
require 'uri'
|
11
|
+
require 'pg'
|
12
|
+
NEW_PG_CONNECTION = proc do
|
13
|
+
uri = URI.parse(QUE_URL)
|
14
|
+
PG::Connection.open :host => uri.host,
|
15
|
+
:user => uri.user,
|
16
|
+
:password => uri.password,
|
17
|
+
:port => uri.port || 5432,
|
18
|
+
:dbname => uri.path[1..-1]
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
# Adapters track information about their connections like which statements
|
24
|
+
# have been prepared, and if Que.connection= is called before each spec, we're
|
25
|
+
# constantly creating new adapters and losing that information, which is bad.
|
26
|
+
# So instead, we hang onto a few adapters and assign them using Que.adapter=
|
27
|
+
# as needed. The plain pg adapter is the default.
|
28
|
+
|
29
|
+
# Also, let Que initialize the adapter itself, to make sure that the
|
30
|
+
# recognition logic works. Similar code can be found in the adapter specs.
|
31
|
+
Que.connection = NEW_PG_CONNECTION.call
|
32
|
+
QUE_ADAPTERS = {:pg => Que.adapter}
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
# We use Sequel to introspect the database in specs.
|
37
|
+
require 'sequel'
|
38
|
+
DB = Sequel.connect(QUE_URL)
|
39
|
+
DB.drop_table? :que_jobs
|
40
|
+
DB.run Que::SQL[:create_table]
|
21
41
|
|
22
42
|
RSpec.configure do |config|
|
23
43
|
config.before do
|
24
|
-
|
25
|
-
|
44
|
+
DB[:que_jobs].delete
|
45
|
+
Que.adapter = QUE_ADAPTERS[:pg]
|
46
|
+
Que.mode = :off
|
47
|
+
Que.sleep_period = nil
|
48
|
+
$logger.messages.clear
|
26
49
|
end
|
27
50
|
end
|
28
51
|
|
29
|
-
Que::Worker.state = :async # Boot up.
|
30
52
|
|
31
|
-
|
32
|
-
#
|
33
|
-
|
34
|
-
|
53
|
+
|
54
|
+
# Set up a dummy logger.
|
55
|
+
Que.logger = $logger = Object.new
|
56
|
+
def $logger.messages; @messages ||= []; end
|
57
|
+
def $logger.method_missing(m, message); messages << message; end
|