beaneater 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,22 +1,31 @@
1
- module Beaneater
1
+ class Beaneater
2
2
  # Beanstalk tube which contains jobs which can be inserted, reserved, et al.
3
- class Tube < PoolCommand
3
+ class Tube
4
4
 
5
5
  # @!attribute name
6
6
  # @return [String] name of the tube
7
- attr_reader :name
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::Pool] pool The beaneater pool for this tube.
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(@pool, 'tube-name')
16
+ # Beaneater::Tube.new(@client, 'tube-name')
15
17
  #
16
- def initialize(pool, name)
18
+ def initialize(client, name)
19
+ @client = client
17
20
  @name = name.to_s
18
21
  @mutex = Mutex.new
19
- super(pool)
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
- options = { :pri => config.default_put_pri, :delay => config.default_put_delay,
37
- :ttr => config.default_put_ttr }.merge(options)
38
- cmd_options = "#{options[:pri]} #{options[:delay]} #{options[:ttr]} #{body.bytesize}"
39
- transmit_to_rand("put #{cmd_options}\r\n#{body}")
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 = transmit_until_res "peek-#{state}", :status => "FOUND"
54
- Job.new(res)
68
+ res = transmit("peek-#{state}")
69
+ Job.new(client, res)
55
70
  end
56
- rescue Beaneater::NotFoundError => ex
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
- pool.tubes.watch!(self.name)
73
- pool.tubes.reserve(timeout, &block)
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 { transmit_to_rand("kick #{bounds}") }
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 = transmit_to_all("stats-tube #{name}", :merge => true)
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
- transmit_to_all("pause-tube #{name} #{delay}")
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
- pool.tubes.watch!(self.name)
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
- pool.tubes.ignore(name)
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 { transmit_to_rand("kick 1") }
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
@@ -1,4 +1,4 @@
1
- module Beaneater
1
+ class Beaneater
2
2
  # Current version of gem.
3
- VERSION = "0.3.3"
4
- end
3
+ VERSION = "1.0.0"
4
+ end
@@ -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::Pool.new(['127.0.0.1:11300'])
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
@@ -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
- assert_equal '127.0.0.1', @bc.connection.peeraddr[3]
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
@@ -4,8 +4,8 @@ require File.expand_path('../test_helper', __FILE__)
4
4
 
5
5
  describe Beaneater::Job do
6
6
  before do
7
- @pool = Beaneater::Pool.new(['localhost'])
8
- @tube = @pool.tubes.find '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 @pool.stats.version.to_f > 1.7
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
@@ -4,9 +4,9 @@ require File.expand_path('../test_helper', __FILE__)
4
4
 
5
5
  describe Beaneater::Jobs do
6
6
  before do
7
- @pool = Beaneater::Pool.new(['localhost'])
8
- @jobs = Beaneater::Jobs.new(@pool)
9
- @tube = @pool.tubes.find('baz')
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
- @pool.tubes.find('tube_success').put("success abort", :pri => 2**31 + 1)
102
- @pool.tubes.find('tube_success').put("success 2", :pri => 1)
103
- @pool.tubes.find('tube_release').put("released")
104
- @pool.tubes.find('tube_buried').put("buried")
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, @pool.tubes.find('tube_success').stats.current_jobs_ready
115
- assert_equal 1, @pool.tubes.find('tube_success').stats.current_jobs_buried
116
- assert_equal 0, @pool.tubes.find('tube_success').stats.current_jobs_reserved
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, @pool.tubes.find('tube_release').peek(:buried).stats.releases
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, @pool.tubes.find('tube_buried').stats.current_jobs_buried
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
@@ -33,9 +33,9 @@ describe "Reading from socket client" do
33
33
  end
34
34
 
35
35
  slept = 0
36
- while @pool.nil?
36
+ while @beanstalk.nil?
37
37
  begin
38
- @pool = Beaneater::Pool.new("localhost:#{@fake_port}")
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 = @pool.tubes[@tube_name].reserve
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
@@ -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
@@ -4,18 +4,18 @@ require File.expand_path('../test_helper', __FILE__)
4
4
 
5
5
  describe Beaneater::Stats do
6
6
  before do
7
- @pool = stub(:transmit_to_all => [{ :body => { 'uptime' => 1, 'cmd-use' => 2 }, :status => "OK"},
8
- {:body => { 'uptime' => 3,'cmd-use' => 4 }, :status => "OK" }])
9
- @stats = Beaneater::Stats.new(@pool)
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 4, @stats[:uptime]
14
+ assert_equal 1, @stats[:uptime]
15
15
  end
16
16
 
17
17
  it "should return stats by underscore key" do
18
- assert_equal 6, @stats[:'cmd_use']
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 4, @stats.uptime
32
+ assert_equal 1, @stats.uptime
33
33
  end
34
34
 
35
35
  it "should return stats by underscore key" do
36
- assert_equal 6, @stats.cmd_use
36
+ assert_equal 2, @stats.cmd_use
37
37
  end
38
38
 
39
39
  it "should raise NoMethodError" do
@@ -6,17 +6,41 @@ require 'minitest/autorun'
6
6
  $:.unshift File.expand_path("../../lib")
7
7
  require 'beaneater'
8
8
  require 'timeout'
9
- require 'mocha/setup' rescue require 'mocha'
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
- # cleanup_tubes!(['foo'], @bp)
16
- def cleanup_tubes!(tubes, bp=nil)
17
- bp ||= @pool
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
- bp.tubes.find(name).clear
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