beaneater 0.3.3 → 1.0.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/CHANGELOG.md +6 -1
- data/README.md +37 -19
- data/examples/demo.rb +1 -2
- data/lib/beaneater.rb +56 -3
- data/lib/beaneater/configuration.rb +3 -1
- data/lib/beaneater/connection.rb +123 -26
- data/lib/beaneater/errors.rb +1 -1
- data/lib/beaneater/job/collection.rb +57 -36
- data/lib/beaneater/job/record.rb +27 -27
- data/lib/beaneater/stats.rb +28 -5
- data/lib/beaneater/stats/fast_struct.rb +1 -1
- data/lib/beaneater/stats/stat_struct.rb +8 -2
- data/lib/beaneater/tube/collection.rb +67 -26
- data/lib/beaneater/tube/record.rb +38 -24
- data/lib/beaneater/version.rb +3 -3
- data/test/beaneater_test.rb +1 -7
- data/test/connection_test.rb +37 -1
- data/test/job_test.rb +3 -7
- data/test/jobs_test.rb +12 -40
- data/test/prompt_regexp_test.rb +4 -3
- data/test/stat_struct_test.rb +10 -0
- data/test/stats_test.rb +7 -7
- data/test/test_helper.rb +30 -6
- data/test/tube_test.rb +9 -20
- data/test/tubes_test.rb +59 -54
- metadata +2 -8
- data/lib/beaneater/pool.rb +0 -166
- data/lib/beaneater/pool_command.rb +0 -79
- data/test/pool_command_test.rb +0 -90
- data/test/pool_test.rb +0 -185
@@ -1,22 +1,31 @@
|
|
1
|
-
|
1
|
+
class Beaneater
|
2
2
|
# Beanstalk tube which contains jobs which can be inserted, reserved, et al.
|
3
|
-
class Tube
|
3
|
+
class Tube
|
4
4
|
|
5
5
|
# @!attribute name
|
6
6
|
# @return [String] name of the tube
|
7
|
-
|
7
|
+
# @!attribute client
|
8
|
+
# @return [Beaneater] returns the client instance
|
9
|
+
attr_reader :name, :client
|
8
10
|
|
9
11
|
# Fetches the specified tube.
|
10
12
|
#
|
11
|
-
# @param [Beaneater
|
13
|
+
# @param [Beaneater] client The beaneater client instance.
|
12
14
|
# @param [String] name The name for this tube.
|
13
15
|
# @example
|
14
|
-
# Beaneater::Tube.new(@
|
16
|
+
# Beaneater::Tube.new(@client, 'tube-name')
|
15
17
|
#
|
16
|
-
def initialize(
|
18
|
+
def initialize(client, name)
|
19
|
+
@client = client
|
17
20
|
@name = name.to_s
|
18
21
|
@mutex = Mutex.new
|
19
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
# Delegates transmit to the connection object.
|
25
|
+
#
|
26
|
+
# @see Beaneater::Connection#transmit
|
27
|
+
def transmit(command, options={})
|
28
|
+
client.connection.transmit(command, options)
|
20
29
|
end
|
21
30
|
|
22
31
|
# Inserts job with specified body onto tube.
|
@@ -33,10 +42,16 @@ module Beaneater
|
|
33
42
|
# @api public
|
34
43
|
def put(body, options={})
|
35
44
|
safe_use do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
serialized_body = config.job_serializer.call(body)
|
46
|
+
|
47
|
+
options = {
|
48
|
+
:pri => config.default_put_pri,
|
49
|
+
:delay => config.default_put_delay,
|
50
|
+
:ttr => config.default_put_ttr
|
51
|
+
}.merge(options)
|
52
|
+
|
53
|
+
cmd_options = "#{options[:pri]} #{options[:delay]} #{options[:ttr]} #{serialized_body.bytesize}"
|
54
|
+
transmit("put #{cmd_options}\r\n#{serialized_body}")
|
40
55
|
end
|
41
56
|
end
|
42
57
|
|
@@ -50,10 +65,10 @@ module Beaneater
|
|
50
65
|
# @api public
|
51
66
|
def peek(state)
|
52
67
|
safe_use do
|
53
|
-
res =
|
54
|
-
Job.new(res)
|
68
|
+
res = transmit("peek-#{state}")
|
69
|
+
Job.new(client, res)
|
55
70
|
end
|
56
|
-
rescue Beaneater::NotFoundError
|
71
|
+
rescue Beaneater::NotFoundError
|
57
72
|
# Return nil if not found
|
58
73
|
nil
|
59
74
|
end
|
@@ -69,8 +84,8 @@ module Beaneater
|
|
69
84
|
#
|
70
85
|
# @api public
|
71
86
|
def reserve(timeout=nil, &block)
|
72
|
-
|
73
|
-
|
87
|
+
client.tubes.watch!(self.name)
|
88
|
+
client.tubes.reserve(timeout, &block)
|
74
89
|
end
|
75
90
|
|
76
91
|
# Kick specified number of jobs from buried to ready state.
|
@@ -82,7 +97,7 @@ module Beaneater
|
|
82
97
|
#
|
83
98
|
# @api public
|
84
99
|
def kick(bounds=1)
|
85
|
-
safe_use {
|
100
|
+
safe_use { transmit("kick #{bounds}") }
|
86
101
|
end
|
87
102
|
|
88
103
|
# Returns related stats for this tube.
|
@@ -93,7 +108,7 @@ module Beaneater
|
|
93
108
|
#
|
94
109
|
# @api public
|
95
110
|
def stats
|
96
|
-
res =
|
111
|
+
res = transmit("stats-tube #{name}")
|
97
112
|
StatStruct.from_hash(res[:body])
|
98
113
|
end
|
99
114
|
|
@@ -106,7 +121,7 @@ module Beaneater
|
|
106
121
|
#
|
107
122
|
# @api public
|
108
123
|
def pause(delay)
|
109
|
-
|
124
|
+
transmit("pause-tube #{name} #{delay}")
|
110
125
|
end
|
111
126
|
|
112
127
|
# Clears all unreserved jobs in all states from the tube
|
@@ -115,13 +130,13 @@ module Beaneater
|
|
115
130
|
# @tube.clear
|
116
131
|
#
|
117
132
|
def clear
|
118
|
-
|
133
|
+
client.tubes.watch!(self.name)
|
119
134
|
%w(delayed buried ready).each do |state|
|
120
135
|
while job = self.peek(state.to_sym)
|
121
136
|
job.delete
|
122
137
|
end
|
123
138
|
end
|
124
|
-
|
139
|
+
client.tubes.ignore(name)
|
125
140
|
rescue Beaneater::UnexpectedResponse
|
126
141
|
# swallow any issues
|
127
142
|
end
|
@@ -144,12 +159,12 @@ module Beaneater
|
|
144
159
|
# @param [Proc] block Beanstalk command to transmit.
|
145
160
|
# @return [Object] Result of block passed
|
146
161
|
# @example
|
147
|
-
# safe_use {
|
162
|
+
# safe_use { transmit("kick 1") }
|
148
163
|
# # => "Response to kick command"
|
149
164
|
#
|
150
165
|
def safe_use(&block)
|
151
166
|
@mutex.lock
|
152
|
-
tubes.use(self.name)
|
167
|
+
client.tubes.use(self.name)
|
153
168
|
yield
|
154
169
|
ensure
|
155
170
|
@mutex.unlock
|
@@ -161,6 +176,5 @@ module Beaneater
|
|
161
176
|
def config
|
162
177
|
Beaneater.configuration
|
163
178
|
end
|
164
|
-
|
165
179
|
end # Tube
|
166
180
|
end # Beaneater
|
data/lib/beaneater/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
class Beaneater
|
2
2
|
# Current version of gem.
|
3
|
-
VERSION = "0.
|
4
|
-
end
|
3
|
+
VERSION = "1.0.0"
|
4
|
+
end
|
data/test/beaneater_test.rb
CHANGED
@@ -2,8 +2,7 @@ require File.expand_path('../test_helper', __FILE__)
|
|
2
2
|
|
3
3
|
describe "beanstalk-client" do
|
4
4
|
before do
|
5
|
-
@beanstalk = Beaneater
|
6
|
-
# @beanstalk = Beaneater::Pool.new(['127.0.0.1:11300', '127.0.0.1:11301'])
|
5
|
+
@beanstalk = Beaneater.new('127.0.0.1:11300')
|
7
6
|
@tubes = ['one', 'two', 'three']
|
8
7
|
|
9
8
|
# Put something on each tube so they exist
|
@@ -108,9 +107,4 @@ describe "beanstalk-client" do
|
|
108
107
|
assert_nil @beanstalk.jobs.find(@job.id)
|
109
108
|
end
|
110
109
|
end
|
111
|
-
|
112
|
-
after do
|
113
|
-
cleanup_tubes!(@tubes, @beanstalk)
|
114
|
-
end
|
115
|
-
|
116
110
|
end
|
data/test/connection_test.rb
CHANGED
@@ -18,13 +18,25 @@ describe Beaneater::Connection do
|
|
18
18
|
|
19
19
|
it "should init connection" do
|
20
20
|
assert_kind_of TCPSocket, @bc.connection
|
21
|
-
|
21
|
+
if @bc.connection.peeraddr[0] == 'AF_INET'
|
22
|
+
assert_equal '127.0.0.1', @bc.connection.peeraddr[3]
|
23
|
+
else
|
24
|
+
assert_equal 'AF_INET6', @bc.connection.peeraddr[0]
|
25
|
+
assert_equal '::1', @bc.connection.peeraddr[3]
|
26
|
+
end
|
22
27
|
assert_equal 11300, @bc.connection.peeraddr[1]
|
23
28
|
end
|
24
29
|
|
25
30
|
it "should raise on invalid connection" do
|
26
31
|
assert_raises(Beaneater::NotConnected) { Beaneater::Connection.new("localhost:8544") }
|
27
32
|
end
|
33
|
+
|
34
|
+
it "should support array connection to single connection" do
|
35
|
+
@bc2 = Beaneater::Connection.new([@host])
|
36
|
+
assert_equal 'localhost', @bc.address
|
37
|
+
assert_equal 'localhost', @bc.host
|
38
|
+
assert_equal 11300, @bc.port
|
39
|
+
end
|
28
40
|
end # new
|
29
41
|
|
30
42
|
describe 'for #transmit' do
|
@@ -60,6 +72,30 @@ describe Beaneater::Connection do
|
|
60
72
|
res = @bc.transmit "put 0 0 100 256\r\n"+(0..255).to_a.pack("c*")
|
61
73
|
assert_equal 'INSERTED', res[:status]
|
62
74
|
end
|
75
|
+
|
76
|
+
it "should retry command with success after one connection failure" do
|
77
|
+
TCPSocket.any_instance.expects(:readline).times(2).
|
78
|
+
raises(EOFError.new).then.
|
79
|
+
returns("DELETED 56\nFOO")
|
80
|
+
|
81
|
+
res = @bc.transmit "delete 56\r\n"
|
82
|
+
assert_equal 'DELETED', res[:status]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should fail after exceeding retries with DrainingError" do
|
86
|
+
TCPSocket.any_instance.expects(:readline).times(3).
|
87
|
+
raises(Beaneater::UnexpectedResponse.from_status("DRAINING", "delete 56"))
|
88
|
+
|
89
|
+
assert_raises(Beaneater::DrainingError) { @bc.transmit "delete 56\r\n" }
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should fail after exceeding reconnect max retries" do
|
93
|
+
# next connection attempts should fail
|
94
|
+
TCPSocket.stubs(:new).times(3).raises(Errno::ECONNREFUSED.new)
|
95
|
+
TCPSocket.any_instance.stubs(:readline).times(1).raises(EOFError.new)
|
96
|
+
|
97
|
+
assert_raises(Beaneater::NotConnected) { @bc.transmit "delete 56\r\n" }
|
98
|
+
end
|
63
99
|
end # transmit
|
64
100
|
|
65
101
|
describe 'for #close' do
|
data/test/job_test.rb
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../test_helper', __FILE__)
|
|
4
4
|
|
5
5
|
describe Beaneater::Job do
|
6
6
|
before do
|
7
|
-
@
|
8
|
-
@tube = @
|
7
|
+
@beanstalk = Beaneater.new('localhost')
|
8
|
+
@tube = @beanstalk.tubes.find 'tube'
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "for #bury" do
|
@@ -139,7 +139,7 @@ describe Beaneater::Job do
|
|
139
139
|
assert_equal 'foo touch', job.body
|
140
140
|
job.bury
|
141
141
|
assert_equal 1, @tube.stats.current_jobs_buried
|
142
|
-
if @
|
142
|
+
if @beanstalk.stats.version.to_f > 1.7
|
143
143
|
job.kick
|
144
144
|
assert_equal 0, @tube.stats.current_jobs_buried
|
145
145
|
assert_equal 1, @tube.stats.current_jobs_ready
|
@@ -244,8 +244,4 @@ describe Beaneater::Job do
|
|
244
244
|
assert_equal 5, @job.delay
|
245
245
|
end
|
246
246
|
end # delay
|
247
|
-
|
248
|
-
after do
|
249
|
-
cleanup_tubes!(['tube'])
|
250
|
-
end
|
251
247
|
end # Beaneater::Job
|
data/test/jobs_test.rb
CHANGED
@@ -4,9 +4,9 @@ require File.expand_path('../test_helper', __FILE__)
|
|
4
4
|
|
5
5
|
describe Beaneater::Jobs do
|
6
6
|
before do
|
7
|
-
@
|
8
|
-
@jobs = Beaneater::Jobs.new(@
|
9
|
-
@tube = @
|
7
|
+
@beanstalk = Beaneater.new('localhost')
|
8
|
+
@jobs = Beaneater::Jobs.new(@beanstalk)
|
9
|
+
@tube = @beanstalk.tubes.find('baz')
|
10
10
|
end
|
11
11
|
|
12
12
|
describe "for #find" do
|
@@ -33,30 +33,6 @@ describe Beaneater::Jobs do
|
|
33
33
|
end
|
34
34
|
end # find
|
35
35
|
|
36
|
-
describe "for #find_all" do
|
37
|
-
before do
|
38
|
-
@time = Time.now.to_i
|
39
|
-
@tube.put("foo find #{@time}")
|
40
|
-
@job = @tube.peek(:ready)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should return job from id" do
|
44
|
-
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should return job using peek" do
|
48
|
-
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should return job using hash syntax" do
|
52
|
-
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should return nil for invalid id" do
|
56
|
-
assert_equal [], @jobs.find_all(-1)
|
57
|
-
end
|
58
|
-
end # find_all
|
59
|
-
|
60
36
|
describe "for #register!" do
|
61
37
|
before do
|
62
38
|
$foo = 0
|
@@ -98,10 +74,10 @@ describe Beaneater::Jobs do
|
|
98
74
|
|
99
75
|
cleanup_tubes!(['tube_success', 'tube_release', 'tube_buried'])
|
100
76
|
|
101
|
-
@
|
102
|
-
@
|
103
|
-
@
|
104
|
-
@
|
77
|
+
@beanstalk.tubes.find('tube_success').put("success abort", :pri => 2**31 + 1)
|
78
|
+
@beanstalk.tubes.find('tube_success').put("success 2", :pri => 1)
|
79
|
+
@beanstalk.tubes.find('tube_release').put("released")
|
80
|
+
@beanstalk.tubes.find('tube_buried').put("buried")
|
105
81
|
|
106
82
|
@jobs.process!(:release_delay => 0)
|
107
83
|
end
|
@@ -111,21 +87,17 @@ describe Beaneater::Jobs do
|
|
111
87
|
end
|
112
88
|
|
113
89
|
it "should clear successful_jobs" do
|
114
|
-
assert_equal 0, @
|
115
|
-
assert_equal 1, @
|
116
|
-
assert_equal 0, @
|
90
|
+
assert_equal 0, @beanstalk.tubes.find('tube_success').stats.current_jobs_ready
|
91
|
+
assert_equal 1, @beanstalk.tubes.find('tube_success').stats.current_jobs_buried
|
92
|
+
assert_equal 0, @beanstalk.tubes.find('tube_success').stats.current_jobs_reserved
|
117
93
|
end
|
118
94
|
|
119
95
|
it "should retry release jobs 2 times" do
|
120
|
-
assert_equal 2, @
|
96
|
+
assert_equal 2, @beanstalk.tubes.find('tube_release').peek(:buried).stats.releases
|
121
97
|
end
|
122
98
|
|
123
99
|
it "should bury unexpected exception" do
|
124
|
-
assert_equal 1, @
|
100
|
+
assert_equal 1, @beanstalk.tubes.find('tube_buried').stats.current_jobs_buried
|
125
101
|
end
|
126
102
|
end # for_process!
|
127
|
-
|
128
|
-
after do
|
129
|
-
cleanup_tubes!(['baz', 'tube_success', 'tube_release', 'tube_buried'])
|
130
|
-
end
|
131
103
|
end # Beaneater::Jobs
|
data/test/prompt_regexp_test.rb
CHANGED
@@ -33,9 +33,9 @@ describe "Reading from socket client" do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
slept = 0
|
36
|
-
while @
|
36
|
+
while @beanstalk.nil?
|
37
37
|
begin
|
38
|
-
@
|
38
|
+
@beanstalk = Beaneater.new("localhost:#{@fake_port}")
|
39
39
|
rescue Beaneater::NotConnected
|
40
40
|
raise 'Could not connect to fake beanstalkd server' if slept > 1
|
41
41
|
sleep 0.1
|
@@ -46,11 +46,12 @@ describe "Reading from socket client" do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it 'should reserve job with full body' do
|
49
|
-
job = @
|
49
|
+
job = @beanstalk.tubes[@tube_name].reserve
|
50
50
|
assert_equal '[first part][second part]', job.body
|
51
51
|
end
|
52
52
|
|
53
53
|
after do
|
54
|
+
@beanstalk.close
|
54
55
|
@fake_server.kill
|
55
56
|
end
|
56
57
|
end
|
data/test/stat_struct_test.rb
CHANGED
@@ -38,4 +38,14 @@ describe Beaneater::StatStruct do
|
|
38
38
|
assert_equal ['foo', 'bar', 'baz', 'under_score'].sort, @struct.keys.sort
|
39
39
|
end
|
40
40
|
end # keys
|
41
|
+
|
42
|
+
describe "for #to_h" do
|
43
|
+
it "should return 4 keys / values" do
|
44
|
+
assert_equal 4, @struct.to_h.size
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return expect hash" do
|
48
|
+
assert_equal [['foo', 'bar'], ['bar', 'baz'], ['baz', 'foo'], ['under_score', 'demo']].sort, @struct.to_h.sort
|
49
|
+
end
|
50
|
+
end # to_h
|
41
51
|
end # Beaneater::StatStruct
|
data/test/stats_test.rb
CHANGED
@@ -4,18 +4,18 @@ require File.expand_path('../test_helper', __FILE__)
|
|
4
4
|
|
5
5
|
describe Beaneater::Stats do
|
6
6
|
before do
|
7
|
-
|
8
|
-
|
9
|
-
@stats = Beaneater::Stats.new(@
|
7
|
+
connection = stub(:transmit => { :body => { 'uptime' => 1, 'cmd-use' => 2 }, :status => "OK"})
|
8
|
+
@beanstalk = stub(:connection => connection)
|
9
|
+
@stats = Beaneater::Stats.new(@beanstalk)
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'for #[]' do
|
13
13
|
it "should return stats by key" do
|
14
|
-
assert_equal
|
14
|
+
assert_equal 1, @stats[:uptime]
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should return stats by underscore key" do
|
18
|
-
assert_equal
|
18
|
+
assert_equal 2, @stats[:'cmd_use']
|
19
19
|
end
|
20
20
|
end # []
|
21
21
|
|
@@ -29,11 +29,11 @@ describe Beaneater::Stats do
|
|
29
29
|
|
30
30
|
describe 'for #method_missing' do
|
31
31
|
it "should return stats by key" do
|
32
|
-
assert_equal
|
32
|
+
assert_equal 1, @stats.uptime
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should return stats by underscore key" do
|
36
|
-
assert_equal
|
36
|
+
assert_equal 2, @stats.cmd_use
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should raise NoMethodError" do
|
data/test/test_helper.rb
CHANGED
@@ -6,17 +6,41 @@ require 'minitest/autorun'
|
|
6
6
|
$:.unshift File.expand_path("../../lib")
|
7
7
|
require 'beaneater'
|
8
8
|
require 'timeout'
|
9
|
-
|
9
|
+
begin
|
10
|
+
require 'mocha/setup'
|
11
|
+
rescue LoadError
|
12
|
+
require 'mocha'
|
13
|
+
end
|
10
14
|
require 'json'
|
11
15
|
|
12
16
|
class MiniTest::Unit::TestCase
|
13
17
|
|
14
|
-
# Cleans up all jobs from tubes
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
+
# Cleans up all jobs from specific tubes
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# cleanup_tubes!(['foo'], @beanstalk)
|
22
|
+
#
|
23
|
+
def cleanup_tubes!(tubes, client=nil)
|
24
|
+
client ||= @beanstalk
|
18
25
|
tubes.each do |name|
|
19
|
-
|
26
|
+
client.tubes.find(name).clear
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Cleans up all jobs from all tubes known to the connection
|
31
|
+
def flush_all(client=nil)
|
32
|
+
client ||= @beanstalk
|
33
|
+
|
34
|
+
# Do not continue if it is a mock or the connection has been closed
|
35
|
+
return if !client.is_a?(Beaneater) || !client.connection.connection
|
36
|
+
|
37
|
+
client.tubes.all.each do |tube|
|
38
|
+
tube.clear
|
20
39
|
end
|
21
40
|
end
|
41
|
+
|
42
|
+
# Run clean up after each test to ensure clean state in all tests
|
43
|
+
def teardown
|
44
|
+
flush_all
|
45
|
+
end
|
22
46
|
end
|