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.
@@ -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