disque_jockey 0.0.1 → 0.0.2
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/README.md +11 -4
- data/bin/disque_jockey +3 -1
- data/disque_jockey.gemspec +1 -0
- data/lib/disque_jockey/cli/help.rb +24 -0
- data/lib/disque_jockey/cli.rb +18 -0
- data/lib/disque_jockey/configuration.rb +19 -14
- data/lib/disque_jockey/exceptions.rb +1 -0
- data/lib/disque_jockey/supervisor.rb +5 -4
- data/lib/disque_jockey/version.rb +1 -1
- data/lib/disque_jockey/worker_group.rb +3 -54
- data/lib/disque_jockey/worker_pool.rb +54 -0
- data/lib/disque_jockey.rb +10 -4
- data/spec/disque_jockey/configuration_spec.rb +41 -6
- data/spec/disque_jockey/supervisor_spec.rb +7 -2
- data/spec/disque_jockey/worker_group_spec.rb +0 -24
- data/spec/disque_jockey/worker_pool_spec.rb +44 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c49083bcd86ac5171c257bd78eeded4abbd5c99f
|
4
|
+
data.tar.gz: 868ababcc280ffa34de1b8270c07b00c04bc299c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fa502414a8a708a693cff041773bb2ae9201d7d0be70dd5fd5eafe2bedd3b6dc31852f7e9f1f516f2dffe52e7998e70923f49eb2a07817d3b768bc683dd632e
|
7
|
+
data.tar.gz: 8dec61c2d6e36a1347147114f00e6290aa2cd2c2d4ae83b76124fdc4f68581e3727208c1f5554b2aa376fd76c212aa2e8e87ed0681bd0e2d1dc00a6f5058f43c
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# DisqueJockey
|
2
2
|
DisqueJockey is a fast, concurrent background job processing framework for the Disque message queue.
|
3
|
-
|
3
|
+
|
4
|
+
## Installation
|
4
5
|
First, you should run a Disque server if you aren't already doing so.
|
5
6
|
Disque source and build instructions can be found at: https://github.com/antirez/disque
|
6
7
|
|
@@ -48,10 +49,17 @@ Your worker class must do two things:
|
|
48
49
|
|
49
50
|
Lastly, you must place your worker in a directory named 'workers'
|
50
51
|
|
51
|
-
|
52
|
+
## Starting Disque Jockey
|
53
|
+
Once your worker is written and placed in a workers directory, you can call `disque_jockey start` from the command line and it will start up your workers and begin delivering jobs to them.
|
54
|
+
|
55
|
+
To see all the command line options, use the help command:
|
56
|
+
```
|
57
|
+
disque_jockey help start
|
58
|
+
```
|
52
59
|
|
60
|
+
To start disque_jockey with the desired options:
|
53
61
|
````
|
54
|
-
disque_jockey
|
62
|
+
disque_jockey start --env=production --daemonize=true --worker-groups=10 --nodes=127.0.0.1:7111,34.45.231.124:4242
|
55
63
|
````
|
56
64
|
|
57
65
|
Messages successfully handled by a worker (ie no exceptions raised from the handle method) will be acknowledged and removed from the queue.
|
@@ -61,6 +69,5 @@ DisqueJockey is not a currently a production-ready system, and there are a numbe
|
|
61
69
|
Here is a list of functionality I'd like to add to DisqueJockey in the near future:
|
62
70
|
- Allow workers to set auto-acknowledge or fast-acknowledge of messages.
|
63
71
|
- Better test coverage around worker groups
|
64
|
-
- Command line options (e.g. environment)
|
65
72
|
- Rails integration (ActiveJob Adapter)
|
66
73
|
- More use cases in the README (e.g. how to use alongside Rails)
|
data/bin/disque_jockey
CHANGED
data/disque_jockey.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.require_paths = ['lib']
|
20
20
|
gem.add_runtime_dependency 'disque'
|
21
21
|
gem.add_runtime_dependency 'logging'
|
22
|
+
gem.add_runtime_dependency 'thor'
|
22
23
|
gem.add_development_dependency('rspec', '~> 3.1', '>= 3.0')
|
23
24
|
gem.add_development_dependency('rake')
|
24
25
|
gem.add_development_dependency('pry')
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module DisqueJockey
|
4
|
+
class CLI < Thor
|
5
|
+
class Help
|
6
|
+
class << self
|
7
|
+
def start
|
8
|
+
<<-EOL
|
9
|
+
Starts disque_jockey processes to start processing Disque jobs.
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
|
13
|
+
$ disque_jockey start --env=production
|
14
|
+
|
15
|
+
$ disque_jockey start --env=development --daemonize=true --work-groups=5
|
16
|
+
|
17
|
+
$ disque_jockey start --nodes=127.0.0.1:6534,54.634.23.43:3452,546.23.124.34:4353
|
18
|
+
EOL
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module DisqueJockey
|
4
|
+
class CLI < Thor
|
5
|
+
desc "start", "Start disque_jockey"
|
6
|
+
option :env, :desc => "set environment"
|
7
|
+
option :worker_groups, :desc => "set number of worker groups"
|
8
|
+
option :log_path, :desc => "set path to logs"
|
9
|
+
option :nodes, :desc => "set nodes"
|
10
|
+
option :daemonize, :type => :boolean, :desc => "run disque_jockey as daemon"
|
11
|
+
long_desc DisqueJockey::CLI::Help.start
|
12
|
+
|
13
|
+
def start
|
14
|
+
DisqueJockey.run!(options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -1,29 +1,34 @@
|
|
1
1
|
module DisqueJockey
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :logger, :worker_groups, :log_path, :env
|
4
|
-
def initialize
|
5
|
-
# set defaults
|
6
|
-
@worker_groups = worker_groups_for_environment
|
7
|
-
@log_path = log_path_for_environment
|
8
|
-
end
|
9
3
|
|
10
|
-
|
11
|
-
|
4
|
+
attr_accessor :logger, :worker_groups, :log_path, :env, :nodes, :daemonize
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@env = options["env"] || ENV["DISQUE_JOCKEY_ENV"] || "development"
|
8
|
+
@worker_groups = (options["worker_groups"] || 2).to_i
|
9
|
+
@log_path = options["log_path"] || log_path_default
|
10
|
+
@nodes = parse_nodes(options["nodes"]) || ["127.0.0.1:7711"]
|
11
|
+
@daemonize = options["daemonize"] || daemonize_default
|
12
12
|
end
|
13
13
|
|
14
14
|
def daemonize?
|
15
|
-
|
15
|
+
@daemonize
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def parse_nodes(nodes)
|
21
|
+
return unless nodes
|
22
|
+
nodes.split(",")
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
env == 'development' ? 2 : 4
|
25
|
+
def log_path_default
|
26
|
+
env == "test" ? "spec/log" : "log"
|
25
27
|
end
|
26
28
|
|
29
|
+
def daemonize_default
|
30
|
+
env != 'development'
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
@@ -0,0 +1 @@
|
|
1
|
+
class NoWorkersFoundError < StandardError; end
|
@@ -32,6 +32,7 @@ module DisqueJockey
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.spawn_worker_groups
|
35
|
+
raise NoWorkersFoundError, "No workers found! See README for instructions on loading workrers" if worker_classes.empty?
|
35
36
|
DisqueJockey.configuration.worker_groups.times { spawn_worker_group }
|
36
37
|
end
|
37
38
|
|
@@ -46,7 +47,7 @@ module DisqueJockey
|
|
46
47
|
# DisqueJockey only exits if it receives a
|
47
48
|
# kill signal
|
48
49
|
loop do
|
49
|
-
@
|
50
|
+
@dead_worker_groups.each do
|
50
51
|
child_pid = @dead_disque_jockeys.shift
|
51
52
|
logger.error "Child worker group exited: #{child_pid}"
|
52
53
|
child_pids.delete(child_pid)
|
@@ -57,7 +58,7 @@ module DisqueJockey
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def self.trap_signals_in_parent
|
60
|
-
@
|
61
|
+
@dead_worker_groups = []
|
61
62
|
%w(QUIT TERM INT ABRT CLD).each do |sig|
|
62
63
|
trap(sig) do
|
63
64
|
if sig == 'CLD'
|
@@ -66,7 +67,7 @@ module DisqueJockey
|
|
66
67
|
# This needs to be reentrant, so we queue up dead child
|
67
68
|
# processes to be handled in the run loop, rather than
|
68
69
|
# acting here
|
69
|
-
@
|
70
|
+
@dead_worker_groups << Process.wait
|
70
71
|
else
|
71
72
|
begin
|
72
73
|
child_pids.each { |pid| Process.kill(sig, pid) }
|
@@ -81,4 +82,4 @@ module DisqueJockey
|
|
81
82
|
|
82
83
|
|
83
84
|
end
|
84
|
-
end
|
85
|
+
end
|
@@ -6,7 +6,6 @@ module DisqueJockey
|
|
6
6
|
|
7
7
|
def initialize(worker_classes = [])
|
8
8
|
@worker_classes = worker_classes # array of classes to instantiate in our group
|
9
|
-
@worker_pool = {} # initialize a hash for storing workers
|
10
9
|
end
|
11
10
|
|
12
11
|
def work!
|
@@ -36,15 +35,11 @@ module DisqueJockey
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
|
-
#
|
40
|
-
# them jobs
|
38
|
+
# for each worker class, create a worker pool and have
|
39
|
+
# them start fetching jobs and working
|
41
40
|
def start_workers
|
42
41
|
@worker_classes.each do |worker_class|
|
43
|
-
|
44
|
-
# Each worker_class (and hence, queue), get its own
|
45
|
-
# thread because the Disque client library blocks
|
46
|
-
# when waiting for a job from a queue.
|
47
|
-
Thread.new { fetch_job_and_work(worker_class) }
|
42
|
+
Thread.new { WorkerPool.new(worker_class).work! }
|
48
43
|
end
|
49
44
|
end
|
50
45
|
|
@@ -58,51 +53,5 @@ module DisqueJockey
|
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
61
|
-
# The worker pool gives us a fixed number of worker instances of each class
|
62
|
-
# to do the work. This could be improved by dynamically instantiating
|
63
|
-
# and removing workers from the pool based on workload. For now, we use
|
64
|
-
# a fixed number.
|
65
|
-
def build_worker_pool(worker_class)
|
66
|
-
Supervisor.logger.info("Launching #{worker_class.thread_count} #{worker_class}s")
|
67
|
-
worker_class.thread_count.times do
|
68
|
-
# Use the Queue class so we access our worker pools
|
69
|
-
# from different threads without issues.
|
70
|
-
@worker_pool[worker_class] ||= Queue.new
|
71
|
-
@worker_pool[worker_class].push worker_class.new(Logger)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Here we actually get jobs to work on and hand them off to worker
|
76
|
-
# instances.
|
77
|
-
def fetch_job_and_work(worker_class)
|
78
|
-
broker = Broker.new
|
79
|
-
loop do
|
80
|
-
# this method blocks until a job is returned
|
81
|
-
_, job_id, job = broker.fetch_message_from(worker_class.queue_name)
|
82
|
-
# Queue#pop will block until a worker becomes available
|
83
|
-
worker = @worker_pool[worker_class].pop
|
84
|
-
# now that we have a worker, give it a thread to do its work in
|
85
|
-
# so we can fetch the next job without waiting.
|
86
|
-
Thread.new do
|
87
|
-
begin
|
88
|
-
# Raise a timeout error if the worker takes too long
|
89
|
-
Timeout::timeout(worker_class.timeout_seconds) { worker.handle(job) }
|
90
|
-
# acknowlege the job once we've handled it
|
91
|
-
broker.acknowledge(job_id)
|
92
|
-
rescue StandardError => exception
|
93
|
-
worker.log_exception(exception)
|
94
|
-
# TODO: Need to implement retry logic
|
95
|
-
# Also should do more helpful logging around worker timeouts
|
96
|
-
# (explain the error, log the job and maybe metadata)
|
97
|
-
end
|
98
|
-
# We're done working, so put the worker back in the pool
|
99
|
-
@worker_pool[worker_class].push(worker)
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
56
|
end
|
108
57
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DisqueJockey
|
2
|
+
class WorkerPool
|
3
|
+
|
4
|
+
def initialize(worker_class)
|
5
|
+
@worker_class = worker_class
|
6
|
+
@pool = Queue.new
|
7
|
+
@broker = Broker.new(DisqueJockey.configuration.nodes)
|
8
|
+
build_worker_pool
|
9
|
+
end
|
10
|
+
|
11
|
+
def work!
|
12
|
+
endless_loop do
|
13
|
+
# fetching from broker blocks until a job is returned
|
14
|
+
_, job_id, job = @broker.fetch_message_from(@worker_class.queue_name)
|
15
|
+
|
16
|
+
with_worker do |worker|
|
17
|
+
Thread.new { handle_job(worker, job, job_id) }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# this method exists so we can stub the endless loop in tests
|
26
|
+
def endless_loop
|
27
|
+
loop { yield }
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_worker
|
31
|
+
# @pool.pop will block until a worker becomes available
|
32
|
+
worker = @pool.pop
|
33
|
+
yield worker
|
34
|
+
@pool.push(worker)
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_job(worker, job, job_id)
|
38
|
+
begin
|
39
|
+
Timeout::timeout(@worker_class.timeout_seconds) { worker.handle(job) }
|
40
|
+
@broker.acknowledge(job_id)
|
41
|
+
rescue StandardError => exception
|
42
|
+
worker.log_exception(exception)
|
43
|
+
# TODO: Need to implement retry logic
|
44
|
+
# Also should do more helpful logging around worker timeouts
|
45
|
+
# (explain the error, log the job and maybe metadata)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_worker_pool
|
50
|
+
@worker_class.thread_count.times { @pool << @worker_class.new(Logger) }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
data/lib/disque_jockey.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require 'disque_jockey/version'
|
2
|
+
require 'disque_jockey/cli/help'
|
3
|
+
require 'disque_jockey/cli'
|
4
|
+
require 'disque_jockey/exceptions'
|
2
5
|
require 'disque_jockey/broker'
|
3
6
|
require 'disque_jockey/logger'
|
4
7
|
require 'disque_jockey/supervisor'
|
5
8
|
require 'disque_jockey/worker'
|
6
9
|
require 'disque_jockey/configuration'
|
10
|
+
require 'disque_jockey/worker_pool'
|
7
11
|
require 'disque_jockey/worker_group'
|
8
12
|
require 'timeout'
|
9
13
|
|
10
|
-
|
11
14
|
module DisqueJockey
|
12
15
|
# raise exceptions in all threads so we don't fail silently
|
13
16
|
Thread.abort_on_exception = true
|
@@ -17,10 +20,13 @@ module DisqueJockey
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.configure
|
20
|
-
yield(
|
23
|
+
yield(configuration)
|
21
24
|
end
|
22
25
|
|
23
|
-
def self.run!
|
26
|
+
def self.run!(options={})
|
27
|
+
@configuration = DisqueJockey::Configuration.new(options)
|
28
|
+
|
24
29
|
DisqueJockey::Supervisor.work!
|
25
30
|
end
|
26
|
-
end
|
31
|
+
end
|
32
|
+
|
@@ -9,11 +9,46 @@ describe DisqueJockey::Configuration do
|
|
9
9
|
it { expect(subject.daemonize?).to eq false }
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
expect(
|
14
|
-
expect(
|
15
|
-
|
16
|
-
|
17
|
-
expect(
|
12
|
+
describe "provides configurable attributes" do
|
13
|
+
it { expect(subject).to respond_to(:log_path) }
|
14
|
+
it { expect(subject).to respond_to(:log_path=) }
|
15
|
+
it { expect(subject).to respond_to(:nodes) }
|
16
|
+
it { expect(subject).to respond_to(:nodes=) }
|
17
|
+
it { expect(subject).to respond_to(:worker_groups) }
|
18
|
+
it { expect(subject).to respond_to(:worker_groups=) }
|
19
|
+
it { expect(subject).to respond_to(:log_path) }
|
20
|
+
it { expect(subject).to respond_to(:log_path=) }
|
21
|
+
it { expect(subject).to respond_to(:env) }
|
22
|
+
it { expect(subject).to respond_to(:env=) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when there are no command line options" do
|
26
|
+
it "uses configuration defaults" do
|
27
|
+
config = DisqueJockey::Configuration.new({})
|
28
|
+
|
29
|
+
expect(config.daemonize).to be true
|
30
|
+
expect(config.env).to eq("test")
|
31
|
+
expect(config.log_path).to eq("spec/log")
|
32
|
+
expect(config.nodes).to eq(["127.0.0.1:7711"])
|
33
|
+
expect(config.worker_groups).to eq(2)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when there are command line options" do
|
38
|
+
it "sets them in the configuration" do
|
39
|
+
cli_opts = {
|
40
|
+
"env" => "production",
|
41
|
+
"daemonize" => true,
|
42
|
+
"worker_groups" => "10",
|
43
|
+
"nodes" => "324.545.23.12:5453,98.437.437.23:43534"
|
44
|
+
}
|
45
|
+
config = DisqueJockey::Configuration.new(cli_opts)
|
46
|
+
expect(config.daemonize).to be true
|
47
|
+
expect(config.env).to eq("production")
|
48
|
+
expect(config.log_path).to eq("log")
|
49
|
+
expect(config.nodes).to eq(["324.545.23.12:5453","98.437.437.23:43534"])
|
50
|
+
expect(config.worker_groups).to eq(10)
|
51
|
+
end
|
18
52
|
end
|
19
53
|
end
|
54
|
+
|
@@ -18,14 +18,19 @@ describe DisqueJockey::Supervisor do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it "::spawn_worker_groups spawns as many worker groups as the config says" do
|
21
|
-
|
22
|
-
expect(DisqueJockey::WorkerGroup).to receive(:new).twice.and_return(group)
|
21
|
+
subject.instance_variable_set(:@worker_classes, ['something'])
|
23
22
|
allow(Process).to receive(:fork).and_yield
|
24
23
|
allow_any_instance_of(DisqueJockey::Configuration).to receive(:worker_groups).and_return 2
|
24
|
+
group = double("WorkerGroup", work!: true)
|
25
|
+
expect(DisqueJockey::WorkerGroup).to receive(:new).twice.and_return(group)
|
25
26
|
expect(group).to receive(:work!).twice
|
26
27
|
subject.send(:spawn_worker_groups)
|
27
28
|
end
|
28
29
|
|
30
|
+
it "::spawn_worker_groups raises an error if there are no worker classes" do
|
31
|
+
expect{subject.send(:spawn_worker_groups)}.to raise_error(NoWorkersFoundError)
|
32
|
+
end
|
33
|
+
|
29
34
|
it "::load_workers loads classes in a workers directory" do
|
30
35
|
expect(Object.const_defined?('FixtureWorker')).to eq false
|
31
36
|
subject.send(:load_workers)
|
@@ -28,30 +28,6 @@ module DisqueJockey
|
|
28
28
|
end
|
29
29
|
subject.new(@worker_classes).work!
|
30
30
|
end
|
31
|
-
|
32
|
-
|
33
|
-
it "gives workers jobs to perform" do
|
34
|
-
allow_any_instance_of(Broker).to receive(:fetch_message_from).and_return(['dummy', 'test_id', 'test job'])
|
35
|
-
expect_any_instance_of(SecondSpecWorker).to receive(:handle).at_least(:once)
|
36
|
-
subject.new(@worker_classes).work!
|
37
|
-
end
|
38
|
-
|
39
|
-
describe "handling logic around jobs" do
|
40
|
-
|
41
|
-
it "times out workers that take too long" do
|
42
|
-
allow_any_instance_of(Broker).to receive(:fetch_message_from).and_return(['dummy', 'test_id', 'test job'])
|
43
|
-
allow_any_instance_of(subject).to receive(:work_until_signal) { sleep(0.2) }
|
44
|
-
expect_any_instance_of(SlowWorker).to receive(:log_exception).at_least(:once)
|
45
|
-
subject.new([SlowWorker]).work!
|
46
|
-
end
|
47
|
-
|
48
|
-
xit "acknowledges jobs if they are processed without errors" do
|
49
|
-
allow_any_instance_of(subject).to receive(:work_until_signal) { sleep(0.1) }
|
50
|
-
allow_any_instance_of(Broker).to receive(:fetch_message_from).and_return(['dummy', 'test_id', 'test job'])
|
51
|
-
expect_any_instance_of(Broker).to receive(:acknowledge).with('test_id').at_least(:once)
|
52
|
-
subject.new([SecondSpecWorker]).work!
|
53
|
-
end
|
54
|
-
end
|
55
31
|
end
|
56
32
|
|
57
33
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'disque_jockey/worker_shared_setup'
|
3
|
+
|
4
|
+
module DisqueJockey
|
5
|
+
describe WorkerPool do
|
6
|
+
include_context "worker setup"
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
allow_any_instance_of(Broker).to receive(:fetch_message_from).and_return(['dummy', 'test_id', 'test job'])
|
10
|
+
allow_any_instance_of(Broker).to receive(:acknowledge)
|
11
|
+
allow_any_instance_of(WorkerPool).to receive(:endless_loop).and_yield
|
12
|
+
allow(Thread).to receive(:new).and_yield
|
13
|
+
end
|
14
|
+
|
15
|
+
it "instantiates the number of workers specified" do
|
16
|
+
expect(SpecWorker).to receive(:new).exactly(SpecWorker.thread_count).times
|
17
|
+
described_class.new(SpecWorker)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "instantiates brokers with nodes from configuration" do
|
21
|
+
expect(Broker).to receive(:new).with(DisqueJockey.configuration.nodes)
|
22
|
+
described_class.new(SpecWorker)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "gives workers jobs to perform" do
|
26
|
+
@mock_worker = double("Worker", handle: true)
|
27
|
+
@mock_worker_class = double("WorkerClass", thread_count: 1, new: @mock_worker, timeout_seconds: 1, queue_name: 'q')
|
28
|
+
worker_pool = WorkerPool.new(@mock_worker_class)
|
29
|
+
expect(@mock_worker).to receive(:handle)
|
30
|
+
worker_pool.work!
|
31
|
+
end
|
32
|
+
|
33
|
+
it "times out workers that take too long" do
|
34
|
+
expect_any_instance_of(SlowWorker).to receive(:log_exception).at_least(:once)
|
35
|
+
WorkerPool.new(SlowWorker).work!
|
36
|
+
end
|
37
|
+
|
38
|
+
it "acknowledges jobs if they are processed without errors" do
|
39
|
+
expect_any_instance_of(Broker).to receive(:acknowledge).with('test_id').at_least(:once)
|
40
|
+
WorkerPool.new(SecondSpecWorker).work!
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: disque_jockey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devin Riley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: disque
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -103,18 +117,23 @@ files:
|
|
103
117
|
- disque_jockey.gemspec
|
104
118
|
- lib/disque_jockey.rb
|
105
119
|
- lib/disque_jockey/broker.rb
|
120
|
+
- lib/disque_jockey/cli.rb
|
121
|
+
- lib/disque_jockey/cli/help.rb
|
106
122
|
- lib/disque_jockey/configuration.rb
|
123
|
+
- lib/disque_jockey/exceptions.rb
|
107
124
|
- lib/disque_jockey/logger.rb
|
108
125
|
- lib/disque_jockey/supervisor.rb
|
109
126
|
- lib/disque_jockey/version.rb
|
110
127
|
- lib/disque_jockey/worker.rb
|
111
128
|
- lib/disque_jockey/worker_group.rb
|
129
|
+
- lib/disque_jockey/worker_pool.rb
|
112
130
|
- spec/disque_jockey/broker_spec.rb
|
113
131
|
- spec/disque_jockey/configuration_spec.rb
|
114
132
|
- spec/disque_jockey/disque_jockey_spec.rb
|
115
133
|
- spec/disque_jockey/logger_spec.rb
|
116
134
|
- spec/disque_jockey/supervisor_spec.rb
|
117
135
|
- spec/disque_jockey/worker_group_spec.rb
|
136
|
+
- spec/disque_jockey/worker_pool_spec.rb
|
118
137
|
- spec/disque_jockey/worker_shared_setup.rb
|
119
138
|
- spec/disque_jockey/worker_spec.rb
|
120
139
|
- spec/fixtures/workers/fixture_worker.rb
|
@@ -151,6 +170,7 @@ test_files:
|
|
151
170
|
- spec/disque_jockey/logger_spec.rb
|
152
171
|
- spec/disque_jockey/supervisor_spec.rb
|
153
172
|
- spec/disque_jockey/worker_group_spec.rb
|
173
|
+
- spec/disque_jockey/worker_pool_spec.rb
|
154
174
|
- spec/disque_jockey/worker_shared_setup.rb
|
155
175
|
- spec/disque_jockey/worker_spec.rb
|
156
176
|
- spec/fixtures/workers/fixture_worker.rb
|