beaneater 0.3.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 454588f4369a9102f949a43c73d7fe8d06de5191
4
- data.tar.gz: e7655c12db30696d1feb41b1f3c6de9c4100115c
2
+ SHA256:
3
+ metadata.gz: 60e34aa7bfb6dc0a66ce540b609fa2ed112af52a7defcb3d7148efdbf9a8d213
4
+ data.tar.gz: 36c9c9cf9a1d2330243f4f8dbd664318bda4b702ecc1c160e9a288255b211764
5
5
  SHA512:
6
- metadata.gz: e523bcdfeb277ed363335be20de8d7114680fe7fa98a7b8a3f7e341547dd0b41290fba35fece3615bd6839ef9381ee8312aac003662e5b2afc4accfdbfa00fbd
7
- data.tar.gz: 0e0d48e4514d953d2acc4bce929a08201912c8f04dc14b0f70bd2ccaa7f7ca2dfbd91ac73156a8542c374fed1b963bd910abe65cfd561d7ff24b7323f1875ff6
6
+ metadata.gz: e447f52b2790b98867e613009d7a31b3cc2af0c116656fe209514000f0a023d662a850328a3242609590f1a2fdfd9f006936f24aaf9b04d86d44f2a7b40a2dd4
7
+ data.tar.gz: 90eca2d3c5db4c0c96a0bfccc774d894c2d942f9ea52979f15a0a5f6b0bb39990299896a994e56f7c60537e015fc152b7fa030293c980498b545e8f5c52cb411
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
4
+ - 2.6
5
+ - 2.7
6
+ - 3.0
7
+ before_install:
8
+ - curl -L https://github.com/kr/beanstalkd/archive/v1.9.tar.gz | tar xz -C /tmp
9
+ - cd /tmp/beanstalkd-1.9/
10
+ - make
11
+ - ./beanstalkd &
12
+ - cd $TRAVIS_BUILD_DIR
13
+ script:
14
+ - bundle install
15
+ - bundle exec rake test:full
data/CHANGELOG.md CHANGED
@@ -1,6 +1,35 @@
1
1
  # CHANGELOG for Beaneater
2
2
 
3
- ## 0.3.2 (Unreleased)
3
+ ## 1.1.1 (April 27th 2021)
4
+
5
+ * Support Ruby 3 keyword arguments (@yahonda)
6
+ * Add CI for Ruby 3 (@yahonda)
7
+
8
+ ## 1.1.0 (April 25th 2021)
9
+
10
+ * 'clear' behavior was failing unexpectedly, swallow issues during delete as well (@bfolkens)
11
+ * Fix assigned but unused variables (@utilum)
12
+ * Fix last_used tube not stored (@albb0920)
13
+ * Fix deprecation warning in ruby 2.7 (@albb0920)
14
+ * Fix watched tubes not restored after reconnect (@albb0920)
15
+ * Fix keyword arguemnt warning (@albb0920)
16
+
17
+ ## 1.0.0 (April 26th 2015)
18
+
19
+ * Beginning from version 1.0.0 the support for `Beaneater::Pool` has been dropped (@alup)
20
+ * `Jobs#find_all` method has been removed, since it is no longer necessary after removing pool (@alup)
21
+ * `Tubes` is now an enumerable allowing `tubes` to be handled as a collection (@Aethelflaed)
22
+
23
+ ## 0.3.3 (August 16th 2014)
24
+
25
+ * Fix failure when job is not defined and fix exception handling for jobs (@nicholasorenrawlings)
26
+ * Add reserve_timeout option to job processing (@nicholasorenrawlings)
27
+ * Add travis-ci badge (@tdg5)
28
+ * Fix tests to run more reliably (@tdg5)
29
+
30
+ ## 0.3.2 (Sept 15 2013)
31
+
32
+ * Fix #29 ExpectedCrlfError name and invocation (@tdg5)
4
33
 
5
34
  ## 0.3.1 (Jun 28 2013)
6
35
 
data/Gemfile CHANGED
@@ -7,4 +7,8 @@ group :development do
7
7
  gem 'redcarpet', '~> 1'
8
8
  gem 'github-markup'
9
9
  gem 'yard'
10
- end
10
+ end
11
+
12
+ group :development, :test do
13
+ gem 'coveralls', :require => false
14
+ end
data/README.md CHANGED
@@ -1,11 +1,14 @@
1
1
  # Beaneater
2
+ [![Build Status](https://secure.travis-ci.org/beanstalkd/beaneater.png)](http://travis-ci.org/beanstalkd/beaneater)
3
+ [![Coverage Status](https://coveralls.io/repos/beanstalkd/beaneater/badge.png?branch=master)](https://coveralls.io/r/beanstalkd/beaneater)
2
4
 
3
5
  Beaneater is the best way to interact with beanstalkd from within Ruby.
4
6
  [Beanstalkd](http://kr.github.com/beanstalkd/) is a simple, fast work queue. Its interface is generic, but was
5
7
  originally designed for reducing the latency of page views in high-volume web applications by
6
8
  running time-consuming tasks asynchronously. Read the [yardocs](http://rdoc.info/github/beanstalkd/beaneater) and/or the
7
- [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md) for more details.
9
+ [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.txt) for more details.
8
10
 
11
+ **Important Note**: This README is **for branch 1.0.x which is under development**. Please switch to latest `0.x` branch for stable version.
9
12
 
10
13
  ## Why Beanstalk?
11
14
 
@@ -81,13 +84,25 @@ gem 'beaneater'
81
84
 
82
85
  and run `bundle install` to install the dependency.
83
86
 
87
+ ## Breaking Changes since 1.0!
88
+
89
+ Starting in 1.0, we removed the concept of the `Beaneater::Pool` which introduced considerable complexity into this gem.
90
+
91
+ * Beginning from version 1.0.0 the support for `Beaneater::Pool` has been dropped.
92
+ The specific feature may be supported again in the next versions as separate module
93
+ or through a separate gem. If you want to use the pool feature you should switch to
94
+ 0.x stable branches instead.
95
+ * `Jobs#find_all` method has been removed, since it is no longer necessary.
96
+
97
+ To manage a pool of beanstalkd instances, we'd prefer to leave the handling to the developer or other higher-level libraries.
98
+
84
99
  ## Quick Overview:
85
100
 
86
101
  The concise summary of how to use beaneater:
87
102
 
88
103
  ```ruby
89
104
  # Connect to pool
90
- @beanstalk = Beaneater::Pool.new(['localhost:11300'])
105
+ @beanstalk = Beaneater.new('localhost:11300')
91
106
  # Enqueue jobs to tube
92
107
  @tube = @beanstalk.tubes["my-tube"]
93
108
  @tube.put '{ "key" : "foo" }', :pri => 5
@@ -95,7 +110,7 @@ The concise summary of how to use beaneater:
95
110
  # Process jobs from tube
96
111
  while @tube.peek(:ready)
97
112
  job = @tube.reserve
98
- puts "job value is #{job.body["key"]}!"
113
+ puts "job value is #{JSON.parse(job.body)["key"]}!"
99
114
  job.delete
100
115
  end
101
116
  # Disconnect the pool
@@ -116,7 +131,8 @@ Beaneater.configure do |config|
116
131
  # config.default_put_pri = 65536
117
132
  # config.default_put_ttr = 120
118
133
  # config.job_parser = lambda { |body| body }
119
- # config.beanstalkd_url = ['localhost:11300']
134
+ # config.job_serializer = lambda { |body| body }
135
+ # config.beanstalkd_url = 'localhost:11300'
120
136
  end
121
137
  ```
122
138
 
@@ -124,18 +140,17 @@ The above options are all defaults, so only include a configuration block if you
124
140
 
125
141
  ### Connection
126
142
 
127
- To interact with a beanstalk queue, first establish a connection by providing a set of addresses:
143
+ To interact with a beanstalk queue, first establish a connection by providing an address:
128
144
 
129
145
  ```ruby
130
- @beanstalk = Beaneater::Pool.new(['10.0.1.5:11300'])
146
+ @beanstalk = Beaneater.new('10.0.1.5:11300')
131
147
 
132
- # Or if ENV['BEANSTALKD_URL] == 'localhost:11300,127.0.0.1:11300'
133
- @beanstalk = Beaneater::Pool.new
134
- @beanstalk.connections.first # => localhost:11300
135
- @beanstalk.connections.last # => 127.0.0.1:11300
148
+ # Or if ENV['BEANSTALKD_URL'] == '127.0.0.1:11300'
149
+ @beanstalk = Beaneater.new
150
+ @beanstalk.connection # => localhost:11300
136
151
  ```
137
152
 
138
- You can conversely close and dispose of a pool at any time with:
153
+ You can conversely close and dispose of a connection at any time with:
139
154
 
140
155
  ```ruby
141
156
  @beanstalk.close
@@ -246,6 +261,16 @@ Beanstalkd can only stores strings as job bodies, but you can easily encode your
246
261
  @tube.put({:foo => 'bar'}.to_json)
247
262
  ```
248
263
 
264
+ Moreover, you can provide a default job serializer by setting the corresponding configuration
265
+ option (`job_serializer`), in order to apply the encoding on each job body which
266
+ is going to be send using the `put` command. For example, to encode a ruby object to JSON format:
267
+
268
+ ```ruby
269
+ Beaneater.configure do |config|
270
+ config.job_serializer = lambda { |body| JSON.dump(body) }
271
+ end
272
+ ```
273
+
249
274
  Each job has various metadata associated such as `priority`, `delay`, and `ttr` which can be
250
275
  specified as part of the `put` command:
251
276
 
@@ -264,7 +289,7 @@ In order to process jobs, the client should first specify the intended tubes to
264
289
  this will default to watching just the `default` tube.
265
290
 
266
291
  ```ruby
267
- @beanstalk = Beaneater::Pool.new(['10.0.1.5:11300'])
292
+ @beanstalk = Beaneater.new('10.0.1.5:11300')
268
293
  @beanstalk.tubes.watch!('tube-name', 'other-tube')
269
294
  ```
270
295
 
@@ -328,13 +353,6 @@ inspected using the 'peek' commands. To find and peek at a particular job based
328
353
  # => <Beaneater::Job id=123 body="foo">
329
354
  ```
330
355
 
331
- You can also `find_all` jobs across all connections:
332
-
333
- ```ruby
334
- @beanstalk.jobs.find_all(123)
335
- # => [<Beaneater::Job id=123 body="foo">, <Beaneater::Job id=123 body="bar">]
336
- ```
337
-
338
356
  or you can peek at jobs within a tube:
339
357
 
340
358
  ```ruby
@@ -411,7 +429,7 @@ are listed below:
411
429
  There are other exceptions that are less common such as `OutOfMemoryError`, `DrainingError`,
412
430
  `DeadlineSoonError`, `InternalError`, `BadFormatError`, `UnknownCommandError`,
413
431
  `ExpectedCRLFError`, `JobTooBigError`, `NotIgnoredError`. Be sure to check the
414
- [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md) for more information.
432
+ [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.txt) for more information.
415
433
 
416
434
 
417
435
  ### Stats
@@ -422,8 +440,9 @@ beanstalk overall:
422
440
  ```ruby
423
441
  # Get overall stats about the job processing that has occurred
424
442
  print @beanstalk.stats
425
- # => { 'current_connections': 1, 'current_jobs_buried': 0, ... }
426
- print @beanstalk.stats.current_connections
443
+ # => #<Beaneater::StatStruct current_jobs_urgent=0, current_jobs_ready=0, current_jobs_reserved=0, current_jobs_delayed=0, current_jobs_buried=0, ...
444
+
445
+ print @beanstalk.stats.current_tubes
427
446
  # => 1
428
447
  ```
429
448
 
@@ -443,7 +462,7 @@ print @beanstalk.jobs[some_job_id].stats
443
462
  # => {'age': 0, 'id': 2, 'state': 'reserved', 'tube': 'default', ... }
444
463
  ```
445
464
 
446
- Be sure to check the [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md) for
465
+ Be sure to check the [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.txt) for
447
466
  more details about the stats commands.
448
467
 
449
468
  ## Resources
@@ -454,8 +473,9 @@ There are other resources helpful when learning about beanstalk:
454
473
  * [Beaneater on Rubygems](https://rubygems.org/gems/beaneater)
455
474
  * [Beanstalkd homepage](http://kr.github.com/beanstalkd/)
456
475
  * [beanstalk on github](https://github.com/kr/beanstalkd)
457
- * [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md)
476
+ * [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.txt)
458
477
  * [Backburner](https://github.com/nesquena/backburner) - Ruby job queue for Rails/Sinatra
478
+ * [BeanCounter](https://github.com/gemeraldbeanstalk/bean_counter) - TestUnit/MiniTest assertions and RSpec matchers for testing code that relies on Beaneater
459
479
 
460
480
  ## Contributors
461
481
 
@@ -463,3 +483,4 @@ There are other resources helpful when learning about beanstalk:
463
483
  - [Nathan Esquenazi](https://github.com/nesquena) - Contributor and co-maintainer
464
484
  - [Keith Rarick](https://github.com/kr) - Much code inspired and adapted from beanstalk-client
465
485
  - [Vidar Hokstad](https://github.com/vidarh) - Replaced telnet with correct TCP socket handling
486
+ - [Andreas Loupasakis](https://github.com/alup) - Improve test coverage, improve job configuration
data/Rakefile CHANGED
@@ -28,4 +28,6 @@ end
28
28
  YARD::Rake::YardocTask.new do |t|
29
29
  t.files = ['lib/beaneater/**/*.rb']
30
30
  t.options = []
31
- end
31
+ end
32
+
33
+ task :default => 'test:full'
data/beaneater.gemspec CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
11
11
  gem.description = %q{Simple beanstalkd client for ruby}
12
12
  gem.summary = %q{Simple beanstalkd client for ruby.}
13
13
  gem.homepage = ""
14
+ gem.license = 'MIT'
14
15
 
15
16
  gem.files = `git ls-files`.split($/)
16
17
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
data/examples/demo.rb CHANGED
@@ -6,8 +6,7 @@ require 'beaneater'
6
6
 
7
7
  # Establish a pool of beanstalks
8
8
  puts step("Connecting to Beanstalk")
9
- bc = Beaneater::Pool.new('localhost')
10
- # bc = Beaneater::Pool.new(['localhost', 'localhost:11301', 'localhost:11302'])
9
+ bc = Beaneater.new('localhost')
11
10
  puts bc
12
11
 
13
12
  # Print out key stats
data/lib/beaneater.rb CHANGED
@@ -1,11 +1,64 @@
1
1
  require 'thread' unless defined?(Mutex)
2
2
 
3
- %w(version configuration errors pool_command pool connection stats tube job).each do |f|
3
+ %w(version configuration errors connection tube job stats).each do |f|
4
4
  require "beaneater/#{f}"
5
5
  end
6
6
 
7
- module Beaneater
8
- # Simple ruby client for beanstalkd.
7
+ class Beaneater
8
+
9
+ # @!attribute connection
10
+ # @return <Beaneater::Connection> returns the associated connection object
11
+ attr_reader :connection
12
+
13
+ # Initialize new instance of Beaneater
14
+ #
15
+ # @param [String] address in the form "host:port"
16
+ # @example
17
+ # Beaneater.new('127.0.0.1:11300')
18
+ #
19
+ # ENV['BEANSTALKD_URL'] = '127.0.0.1:11300'
20
+ # @b = Beaneater.new
21
+ # @b.connection.host # => '127.0.0.1'
22
+ # @b.connection.port # => '11300'
23
+ #
24
+ def initialize(address=nil)
25
+ @connection = Connection.new(address)
26
+ end
27
+
28
+ # Returns Beaneater::Tubes object for accessing tube related functions.
29
+ #
30
+ # @return [Beaneater::Tubes] tubes object
31
+ # @api public
32
+ def tubes
33
+ @tubes ||= Beaneater::Tubes.new(self)
34
+ end
35
+
36
+ # Returns Beaneater::Jobs object for accessing job related functions.
37
+ #
38
+ # @return [Beaneater::Jobs] jobs object
39
+ # @api public
40
+ def jobs
41
+ @jobs ||= Beaneater::Jobs.new(self)
42
+ end
43
+
44
+ # Returns Beaneater::Stats object for accessing beanstalk stats.
45
+ #
46
+ # @return [Beaneater::Stats] stats object
47
+ # @api public
48
+ def stats
49
+ @stats ||= Stats.new(self)
50
+ end
51
+
52
+ # Closes the related connection
53
+ #
54
+ # @example
55
+ # @beaneater_instance.close
56
+ #
57
+ def close
58
+ connection.close if connection
59
+ end
60
+
61
+ protected
9
62
 
10
63
  class << self
11
64
  # Yields a configuration block
@@ -29,4 +82,4 @@ module Beaneater
29
82
  @_configuration ||= Configuration.new
30
83
  end
31
84
  end
32
- end # Beaneater
85
+ end # Beaneater
@@ -1,9 +1,10 @@
1
- module Beaneater
1
+ class Beaneater
2
2
  class Configuration
3
3
  attr_accessor :default_put_delay # default delay value to put a job
4
4
  attr_accessor :default_put_pri # default priority value to put a job
5
5
  attr_accessor :default_put_ttr # default ttr value to put a job
6
6
  attr_accessor :job_parser # default job_parser to parse job body
7
+ attr_accessor :job_serializer # default serializer for job body
7
8
  attr_accessor :beanstalkd_url # default beanstalkd url
8
9
 
9
10
  def initialize
@@ -11,6 +12,7 @@ module Beaneater
11
12
  @default_put_pri = 65536
12
13
  @default_put_ttr = 120
13
14
  @job_parser = lambda { |body| body }
15
+ @job_serializer = lambda { |body| body }
14
16
  @beanstalkd_url = nil
15
17
  end
16
18
  end # Configuration
@@ -1,10 +1,16 @@
1
1
  require 'yaml'
2
2
  require 'socket'
3
3
 
4
- module Beaneater
4
+ class Beaneater
5
5
  # Represents a connection to a beanstalkd instance.
6
6
  class Connection
7
7
 
8
+ # Default number of retries to send a command to a connection
9
+ MAX_RETRIES = 3
10
+
11
+ # Default retry interval
12
+ DEFAULT_RETRY_INTERVAL = 1
13
+
8
14
  # @!attribute address
9
15
  # @return [String] returns Beanstalkd server address
10
16
  # @example
@@ -21,6 +27,12 @@ module Beaneater
21
27
  # @return [Net::TCPSocket] returns connection object
22
28
  attr_reader :address, :host, :port, :connection
23
29
 
30
+ # @!attribute tubes_watched
31
+ # @returns [Array<String>] returns currently watched tube names
32
+ # @!attribute tube_used
33
+ # @returns [String] returns currently used tube name
34
+ attr_accessor :tubes_watched, :tube_used
35
+
24
36
  # Default port value for beanstalk connection
25
37
  DEFAULT_PORT = 11300
26
38
 
@@ -28,13 +40,23 @@ module Beaneater
28
40
  #
29
41
  # @param [String] address beanstalkd instance address.
30
42
  # @example
31
- # Beaneater::Connection.new('localhost')
32
- # Beaneater::Connection.new('localhost:11300')
43
+ # Beaneater::Connection.new('127.0.0.1')
44
+ # Beaneater::Connection.new('127.0.0.1:11300')
45
+ #
46
+ # ENV['BEANSTALKD_URL'] = '127.0.0.1:11300'
47
+ # @b = Beaneater.new
48
+ # @b.connection.host # => '127.0.0.1'
49
+ # @b.connection.port # => '11300'
33
50
  #
34
51
  def initialize(address)
35
- @address = address
36
- @connection = establish_connection
52
+ @address = address || _host_from_env || Beaneater.configuration.beanstalkd_url
37
53
  @mutex = Mutex.new
54
+ @tube_used = 'default'
55
+ @tubes_watched = ['default']
56
+
57
+ establish_connection
58
+ rescue
59
+ _raise_not_connected!
38
60
  end
39
61
 
40
62
  # Send commands to beanstalkd server via connection.
@@ -43,18 +65,19 @@ module Beaneater
43
65
  # @param [String] command Beanstalkd command
44
66
  # @return [Array<Hash{String => String, Number}>] Beanstalkd command response
45
67
  # @example
68
+ # @conn = Beaneater::Connection.new
46
69
  # @conn.transmit('bury 123')
70
+ # @conn.transmit('stats')
47
71
  #
48
- def transmit(command, options={})
49
- @mutex.synchronize do
50
- if connection
72
+ def transmit(command, **options)
73
+ _with_retry(**options.slice(:retry_interval, :init)) do
74
+ @mutex.synchronize do
75
+ _raise_not_connected! unless connection
76
+
51
77
  command = command.force_encoding('ASCII-8BIT') if command.respond_to?(:force_encoding)
52
78
  connection.write(command.to_s + "\r\n")
53
- res = connection.gets
54
- raise_not_connected! unless res
79
+ res = connection.readline
55
80
  parse_response(command, res)
56
- else # no connection
57
- raise_not_connected!
58
81
  end
59
82
  end
60
83
  end
@@ -65,8 +88,10 @@ module Beaneater
65
88
  # @conn.close
66
89
  #
67
90
  def close
68
- @connection.close
69
- @connection = nil
91
+ if @connection
92
+ @connection.close
93
+ @connection = nil
94
+ end
70
95
  end
71
96
 
72
97
  # Returns string representation of job.
@@ -79,23 +104,30 @@ module Beaneater
79
104
  end
80
105
  alias :inspect :to_s
81
106
 
107
+ def add_to_watched(tube_name)
108
+ @tubes_watched << tube_name
109
+ @tubes_watched.uniq
110
+ end
111
+
112
+ def remove_from_watched(tube_name)
113
+ @tubes_watched.delete(tube_name)
114
+ end
115
+
82
116
  protected
83
117
 
84
118
  # Establish a connection based on beanstalk address.
85
119
  #
86
120
  # @return [Net::TCPSocket] connection for specified address.
87
- # @raise [Beanstalk::NotConnected] Could not connect to specified beanstalkd instance.
121
+ # @raise [Beaneater::NotConnected] Could not connect to specified beanstalkd instance.
88
122
  # @example
89
123
  # establish_connection('localhost:3005')
90
124
  #
91
125
  def establish_connection
92
- @match = address.split(':')
93
- @host, @port = @match[0], Integer(@match[1] || DEFAULT_PORT)
94
- TCPSocket.new @host, @port
95
- rescue Errno::ECONNREFUSED => e
96
- raise NotConnected, "Could not connect to '#{@host}:#{@port}'"
97
- rescue Exception => ex
98
- raise NotConnected, "#{ex.class}: #{ex}"
126
+ @address = address.first if address.is_a?(Array)
127
+ match = address.split(':')
128
+ @host, @port = match[0], Integer(match[1] || DEFAULT_PORT)
129
+
130
+ @connection = TCPSocket.new @host, @port
99
131
  end
100
132
 
101
133
  # Parses the response and returns the useful beanstalk response.
@@ -103,11 +135,11 @@ module Beaneater
103
135
  #
104
136
  # @param [String] cmd Beanstalk command transmitted
105
137
  # @param [String] res Telnet command response
106
- # @return [Array<Hash{String => String, Number}>] Beanstalk response with `status`, `id`, `body`, and `connection`
138
+ # @return [Array<Hash{String => String, Number}>] Beanstalk response with `status`, `id`, `body`
107
139
  # @raise [Beaneater::UnexpectedResponse] Response from beanstalk command was an error status
108
140
  # @example
109
141
  # parse_response("delete 56", "DELETED 56\nFOO")
110
- # # => { :body => "FOO", :status => "DELETED", :id => 56, :connection => <Connection> }
142
+ # # => { :body => "FOO", :status => "DELETED", :id => 56 }
111
143
  #
112
144
  def parse_response(cmd, res)
113
145
  status = res.chomp
@@ -120,12 +152,12 @@ module Beaneater
120
152
  raw_body = connection.read(bytes_size)
121
153
  body = status == 'OK' ? YAML.load(raw_body) : config.job_parser.call(raw_body)
122
154
  crlf = connection.read(2) # \r\n
123
- raise ExpectedCRLFError if crlf != "\r\n"
155
+ raise ExpectedCrlfError.new('EXPECTED_CRLF', cmd) if crlf != "\r\n"
124
156
  end
125
157
  id = body_values[1]
126
- response = { :status => status, :body => body }
158
+ response = { :status => status }
127
159
  response[:id] = id if id
128
- response[:connection] = self
160
+ response[:body] = body if body
129
161
  response
130
162
  end
131
163
 
@@ -136,10 +168,77 @@ module Beaneater
136
168
  Beaneater.configuration
137
169
  end
138
170
 
171
+ private
172
+
173
+ def _initialize_tubes
174
+ if @tubes_watched != ['default']
175
+ tubes_watched.each do |t|
176
+ transmit("watch #{t}", init: false)
177
+ end
178
+
179
+ transmit("ignore default", init: false)
180
+ end
181
+
182
+ transmit("use #{tube_used}", init: false) if @tube_used != 'default'
183
+ end
184
+
185
+ # Wrapper method for capturing certain failures and retry the payload block
186
+ #
187
+ # @param [Proc] block The command to execute.
188
+ # @param [Integer] retry_interval The time to wait before the next retry
189
+ # @param [Integer] tries The maximum number of tries in draining mode
190
+ # @return [Object] Result of the block passed
191
+ #
192
+ def _with_retry(retry_interval: DEFAULT_RETRY_INTERVAL, init: true, tries: MAX_RETRIES, &block)
193
+ yield
194
+ rescue EOFError, Errno::ECONNRESET, Errno::EPIPE,
195
+ Errno::ECONNREFUSED => ex
196
+ _reconnect(ex, retry_interval)
197
+ _initialize_tubes if init
198
+ retry
199
+ rescue Beaneater::DrainingError
200
+ tries -= 1
201
+ if tries.zero?
202
+ close
203
+ raise
204
+ end
205
+ sleep(retry_interval)
206
+ retry
207
+ end
208
+
209
+ # Tries to re-establish connection to the beanstalkd
210
+ #
211
+ # @param [Exception] original_exception The exception caused the retry
212
+ # @param [Integer] retry_interval The time to wait before the next reconnect
213
+ # @param [Integer] tries The maximum number of attempts to reconnect
214
+ def _reconnect(original_exception, retry_interval, tries=MAX_RETRIES)
215
+ close
216
+ establish_connection
217
+ rescue Errno::ECONNREFUSED
218
+ tries -= 1
219
+ if tries.zero?
220
+ _raise_not_connected!
221
+ end
222
+ sleep(retry_interval || DEFAULT_RETRY_INTERVAL)
223
+ retry
224
+ end
225
+
226
+ # The host provided by BEANSTALKD_URL environment variable, if available.
227
+ #
228
+ # @return [String] A beanstalkd host address
229
+ # @example
230
+ # ENV['BEANSTALKD_URL'] = "localhost:1212"
231
+ # # => 'localhost:1212'
232
+ #
233
+ def _host_from_env
234
+ ENV['BEANSTALKD_URL'].respond_to?(:length) && ENV['BEANSTALKD_URL'].length > 0 && ENV['BEANSTALKD_URL'].strip
235
+ end
236
+
139
237
  # Raises an error to be triggered when the connection has failed
140
238
  # @raise [Beaneater::NotConnected] Beanstalkd is no longer connected
141
- def raise_not_connected!
142
- raise NotConnected, "Connection to beanstalk '#{@host}:#{@port}' is closed!"
239
+ def _raise_not_connected!
240
+ raise Beaneater::NotConnected, "Connection to beanstalk '#{@host}:#{@port}' is closed!"
143
241
  end
242
+
144
243
  end # Connection
145
244
  end # Beaneater