disque_jockey 0.0.2 → 0.0.3
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 +20 -0
- data/lib/disque_jockey/broker.rb +20 -4
- data/lib/disque_jockey/version.rb +1 -1
- data/lib/disque_jockey/worker.rb +8 -2
- data/lib/disque_jockey/worker_pool.rb +3 -3
- data/spec/disque_jockey/broker_spec.rb +29 -4
- data/spec/disque_jockey/worker_pool_spec.rb +15 -2
- data/spec/disque_jockey/worker_shared_setup.rb +2 -1
- data/spec/disque_jockey/worker_spec.rb +15 -7
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e595757036b4f0fa828fcb9dda551db3f211ed7e
|
4
|
+
data.tar.gz: 81687ba961860e23ffd2b877b81166b8c8f3ea31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bbd8ab91aba802d6f1c7364fe833eef0f20ee0813593cdad4fe3bb7c63c1508cf34db86f73530461283d5946c3520c472a5cfe48e0a1474c775c7b618972bd7
|
7
|
+
data.tar.gz: 4f294a19102ce434dd3c55d97425cde430680903e1241a2ef44d02c53dae2a7eecd9f8a796570d9cbba161ba0974889c2c732349ac8e5e807926f1c5d331c345
|
data/README.md
CHANGED
@@ -63,6 +63,26 @@ disque_jockey start --env=production --daemonize=true --worker-groups=10 --node
|
|
63
63
|
````
|
64
64
|
|
65
65
|
Messages successfully handled by a worker (ie no exceptions raised from the handle method) will be acknowledged and removed from the queue.
|
66
|
+
## Worker Configuration
|
67
|
+
DisqueJockey::Worker implements some class methods that help you configure your worker. You call them the same way you call the `subscribe_to` method, at the top of your class.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
require 'disque_jockey'
|
71
|
+
class HighlyConfiguredWorker < DisqueJockey::Worker
|
72
|
+
subscribe_to 'example-queue'
|
73
|
+
threads 7
|
74
|
+
fast_ack true
|
75
|
+
timeout 5
|
76
|
+
|
77
|
+
def handle(job)
|
78
|
+
logger.info("Peforming job: #{job}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
- *Fast Acknowledgements*: call ````fast_ack true```` to use FASTACKs (https://github.com/antirez/disque#fast-acknowledges) in disque to acknowledge your messages. Please note that fast_ack will make it more likely you will process a job more than once in the event of a network partition. fast_ack is false by default.
|
83
|
+
- *Threads*: To devote more threads to your worker class use ````threads 5```` . Threads are set to two by default and have a maximum value of 10.
|
84
|
+
- *Timeout*: To set the number of seconds your worker will process a job until raising a TimeoutError, use ````timeout 45````. Timeout is set to 30 seconds by default and has a maximum value of 3600 seconds (one hour).
|
85
|
+
|
66
86
|
|
67
87
|
##Roadmap:
|
68
88
|
DisqueJockey is not a currently a production-ready system, and there are a number of goals for it that have not been met yet.
|
data/lib/disque_jockey/broker.rb
CHANGED
@@ -13,10 +13,26 @@ module DisqueJockey
|
|
13
13
|
|
14
14
|
def acknowledge(job_id)
|
15
15
|
response = @client.call('ACKJOB', job_id)
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
raise_error_or_return_true(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def fast_acknowledge(job_id)
|
20
|
+
response = @client.call('FASTACK', job_id)
|
21
|
+
raise_error_or_return_true(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
def publish(*args)
|
25
|
+
@client.push(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# If there is an error acking the job the Disque client
|
31
|
+
# *returns* an error object but doesn't raise it,
|
32
|
+
# so we raise it here ourselves.
|
33
|
+
def raise_error_or_return_true(response)
|
19
34
|
response.is_a?(RuntimeError) ? raise(response) : true
|
20
35
|
end
|
36
|
+
|
21
37
|
end
|
22
|
-
end
|
38
|
+
end
|
data/lib/disque_jockey/worker.rb
CHANGED
@@ -11,13 +11,18 @@ module DisqueJockey
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class << self
|
14
|
-
attr_reader :queue_name, :thread_count, :timeout_seconds
|
14
|
+
attr_reader :queue_name, :thread_count, :timeout_seconds, :use_fast_ack
|
15
15
|
|
16
16
|
# This worker class will subscribe to queue
|
17
17
|
def subscribe_to(queue)
|
18
18
|
@queue_name = queue
|
19
19
|
end
|
20
20
|
|
21
|
+
# whehter to use Disque fast acknowledgements
|
22
|
+
def fast_ack(value)
|
23
|
+
@use_fast_ack = !!value
|
24
|
+
end
|
25
|
+
|
21
26
|
# minimum number of worker instances of a given worker class.
|
22
27
|
def threads(size)
|
23
28
|
@thread_count = [[size, 1].max, 10].min
|
@@ -36,10 +41,11 @@ module DisqueJockey
|
|
36
41
|
# these are the defaults
|
37
42
|
type.threads 2
|
38
43
|
type.timeout 30
|
44
|
+
type.fast_ack false
|
39
45
|
# register the new worker type so we can start giving it jobs
|
40
46
|
Supervisor.register_worker(type)
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
44
50
|
end
|
45
|
-
end
|
51
|
+
end
|
@@ -37,7 +37,7 @@ module DisqueJockey
|
|
37
37
|
def handle_job(worker, job, job_id)
|
38
38
|
begin
|
39
39
|
Timeout::timeout(@worker_class.timeout_seconds) { worker.handle(job) }
|
40
|
-
@broker.acknowledge(job_id)
|
40
|
+
@worker_class.use_fast_ack ? @broker.fast_acknowledge(job_id) : @broker.acknowledge(job_id)
|
41
41
|
rescue StandardError => exception
|
42
42
|
worker.log_exception(exception)
|
43
43
|
# TODO: Need to implement retry logic
|
@@ -47,8 +47,8 @@ module DisqueJockey
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def build_worker_pool
|
50
|
-
@worker_class.thread_count.times { @pool << @worker_class.new(Logger) }
|
50
|
+
@worker_class.thread_count.times { @pool << @worker_class.new(Logger) }
|
51
51
|
end
|
52
52
|
|
53
53
|
end
|
54
|
-
end
|
54
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
module DisqueJockey
|
3
3
|
describe Broker do
|
4
|
-
# Note: You actually have to run a Disque server
|
4
|
+
# Note: You actually have to run a Disque server
|
5
5
|
# locally for these tests to pass
|
6
6
|
before(:all) do
|
7
7
|
begin
|
@@ -34,7 +34,7 @@ module DisqueJockey
|
|
34
34
|
end
|
35
35
|
|
36
36
|
describe '#acknowledge' do
|
37
|
-
it "
|
37
|
+
it "removes job from queue and returns true if it succeeds" do
|
38
38
|
@client.call('DEBUG', 'FLUSHALL')
|
39
39
|
job_id = @client.push('test_queue', 'test job', 1000)
|
40
40
|
expect(@client.call('QLEN', 'test_queue')).to eq 1
|
@@ -43,9 +43,34 @@ module DisqueJockey
|
|
43
43
|
end
|
44
44
|
|
45
45
|
it "raises an error for a bad job id" do
|
46
|
-
expect{@broker.acknowledge('bad_id')}.to raise_error(RuntimeError)
|
46
|
+
expect{ @broker.acknowledge('bad_id') }.to raise_error(RuntimeError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#publish" do
|
51
|
+
it "publishes a job to Disque" do
|
52
|
+
test_queue = 'publish_test_queue'
|
53
|
+
test_job = 'job'
|
54
|
+
@broker.publish(test_queue, test_job, 1000)
|
55
|
+
fetched = @client.fetch(from: ['publish_test_queue']).first
|
56
|
+
expect(fetched.first).to eq test_queue
|
57
|
+
expect(fetched.last).to eq test_job
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#fast_acknowledge" do
|
62
|
+
it "raises an error for a bad job id" do
|
63
|
+
expect{@broker.fast_acknowledge('bad_id')}.to raise_error(RuntimeError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "acknowledges jobs" do
|
67
|
+
@client.call('DEBUG', 'FLUSHALL')
|
68
|
+
job_id = @client.push('test_queue', 'test job', 1000)
|
69
|
+
expect(@client.call('QLEN', 'test_queue')).to eq 1
|
70
|
+
expect(@broker.fast_acknowledge(job_id)).to eq true
|
71
|
+
expect(@client.call('QLEN', 'test_queue')).to eq 0
|
47
72
|
end
|
48
73
|
end
|
49
74
|
|
50
75
|
end
|
51
|
-
end
|
76
|
+
end
|
@@ -24,7 +24,13 @@ module DisqueJockey
|
|
24
24
|
|
25
25
|
it "gives workers jobs to perform" do
|
26
26
|
@mock_worker = double("Worker", handle: true)
|
27
|
-
@mock_worker_class = double(
|
27
|
+
@mock_worker_class = double(
|
28
|
+
"WorkerClass",
|
29
|
+
thread_count: 1,
|
30
|
+
new: @mock_worker,
|
31
|
+
timeout_seconds: 1,
|
32
|
+
queue_name: 'q',
|
33
|
+
use_fast_ack: false)
|
28
34
|
worker_pool = WorkerPool.new(@mock_worker_class)
|
29
35
|
expect(@mock_worker).to receive(:handle)
|
30
36
|
worker_pool.work!
|
@@ -36,9 +42,16 @@ module DisqueJockey
|
|
36
42
|
end
|
37
43
|
|
38
44
|
it "acknowledges jobs if they are processed without errors" do
|
45
|
+
SecondSpecWorker.fast_ack(false)
|
39
46
|
expect_any_instance_of(Broker).to receive(:acknowledge).with('test_id').at_least(:once)
|
40
47
|
WorkerPool.new(SecondSpecWorker).work!
|
41
48
|
end
|
42
49
|
|
50
|
+
it "fast_acknowledges jobs if the worker uses fast_ack" do
|
51
|
+
SecondSpecWorker.fast_ack(true)
|
52
|
+
expect_any_instance_of(Broker).to receive(:fast_acknowledge).with('test_id').at_least(:once)
|
53
|
+
WorkerPool.new(SecondSpecWorker).work!
|
54
|
+
end
|
55
|
+
|
43
56
|
end
|
44
|
-
end
|
57
|
+
end
|
@@ -6,8 +6,8 @@ describe DisqueJockey::Worker do
|
|
6
6
|
include_context "worker setup"
|
7
7
|
|
8
8
|
it "defines class methods" do
|
9
|
-
[ :queue_name, :thread_count, :timeout_seconds,
|
10
|
-
:subscribe_to, :timeout, :threads
|
9
|
+
[ :queue_name, :thread_count, :timeout_seconds,
|
10
|
+
:subscribe_to, :timeout, :threads, :fast_ack, :use_fast_ack
|
11
11
|
].each do |method|
|
12
12
|
expect(DisqueJockey::Worker).to respond_to(method)
|
13
13
|
end
|
@@ -24,26 +24,34 @@ describe DisqueJockey::Worker do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
context "defaults" do
|
27
|
-
it "
|
27
|
+
it "timeout is 30 seconds" do
|
28
28
|
expect(SpecWorker.timeout_seconds).to be(30)
|
29
29
|
end
|
30
30
|
|
31
|
-
it "
|
31
|
+
it "thread_count is 2" do
|
32
32
|
expect(SpecWorker.thread_count).to be(2)
|
33
33
|
end
|
34
|
+
|
35
|
+
it "use_fast_ack is false" do
|
36
|
+
expect(SpecWorker.use_fast_ack).to eq false
|
37
|
+
end
|
38
|
+
|
34
39
|
end
|
35
40
|
|
36
41
|
context "class methods"
|
37
42
|
context "overrides" do
|
38
|
-
|
43
|
+
|
44
|
+
it "allows overrides for timeout, threads, and fast_ack" do
|
45
|
+
# These traits are set in worker_shared_setup.rb
|
39
46
|
expect(SecondSpecWorker.timeout_seconds).to be(1)
|
40
47
|
expect(SecondSpecWorker.thread_count).to be(1)
|
48
|
+
expect(SecondSpecWorker.use_fast_ack).to be(true)
|
41
49
|
end
|
42
50
|
end
|
43
|
-
|
51
|
+
|
44
52
|
context "instance methods"
|
45
53
|
describe "#initialize" do
|
46
|
-
before do
|
54
|
+
before do
|
47
55
|
@logger = double(:logger, info: true, error: true, warn: true)
|
48
56
|
allow(@logger).to receive(:new).and_return(@logger)
|
49
57
|
end
|