beaneater 0.3.0 → 1.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 83a6a5bc5d6a0e34828c5b011ca65b3bb99a296ab0d038b348279fd7b5bbf842
4
+ data.tar.gz: 30e307f3cb14d2d078cfc2eb23219add703535b2a2c9e8212b60dd54eb808bd9
5
+ SHA512:
6
+ metadata.gz: 820d14df0a37f2d3afd63db394a8d971a0e98436331a67b989e4c58335f1d3803f79b233b261c096069c511cba5ff77d7bf0eb887f14a9f61b39251d9ac8ea12
7
+ data.tar.gz: ed53e2479c36ce9e2af27f3e63a00c3540e935fcc822414649ae2135daa93d59cc14154f71c70e6d02a9f53a42d11b360fe01808350915a85b91abd8ffc95056
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
4
+ - 2.6
5
+ - 2.7
6
+ before_install:
7
+ - curl -L https://github.com/kr/beanstalkd/archive/v1.9.tar.gz | tar xz -C /tmp
8
+ - cd /tmp/beanstalkd-1.9/
9
+ - make
10
+ - ./beanstalkd &
11
+ - cd $TRAVIS_BUILD_DIR
12
+ script:
13
+ - bundle install
14
+ - bundle exec rake test:full
data/CHANGELOG.md CHANGED
@@ -1,6 +1,36 @@
1
1
  # CHANGELOG for Beaneater
2
2
 
3
- ## 0.3.1 (Unreleased)
3
+ ## 1.1.0 (April 25th 2021)
4
+
5
+ * 'clear' behavior was failing unexpectedly, swallow issues during delete as well (@bfolkens)
6
+ * Fix assigned but unused variables (@utilum)
7
+ * Fix last_used tube not stored (@albb0920)
8
+ * Fix deprecation warning in ruby 2.7 (@albb0920)
9
+ * Fix watched tubes not restored after reconnect (@albb0920)
10
+ * Fix keyword arguemnt warning (@albb0920)
11
+
12
+ ## 1.0.0 (April 26th 2015)
13
+
14
+ * Beginning from version 1.0.0 the support for `Beaneater::Pool` has been dropped (@alup)
15
+ * `Jobs#find_all` method has been removed, since it is no longer necessary after removing pool (@alup)
16
+ * `Tubes` is now an enumerable allowing `tubes` to be handled as a collection (@Aethelflaed)
17
+
18
+ ## 0.3.3 (August 16th 2014)
19
+
20
+ * Fix failure when job is not defined and fix exception handling for jobs (@nicholasorenrawlings)
21
+ * Add reserve_timeout option to job processing (@nicholasorenrawlings)
22
+ * Add travis-ci badge (@tdg5)
23
+ * Fix tests to run more reliably (@tdg5)
24
+
25
+ ## 0.3.2 (Sept 15 2013)
26
+
27
+ * Fix #29 ExpectedCrlfError name and invocation (@tdg5)
28
+
29
+ ## 0.3.1 (Jun 28 2013)
30
+
31
+ * Fixes issue with "chomp" nil exception when losing connection (Thanks @simao)
32
+ * Better handling of unknown or invalid commands during transmit
33
+ * Raise proper CRLF exception (Thanks @carlosmoutinho)
4
34
 
5
35
  ## 0.3.0 (Jan 23 2013)
6
36
 
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::Connection.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
@@ -390,7 +408,9 @@ Processing runs the following steps:
390
408
  1. If other exception occurs, call 'bury' (error)
391
409
  1. Repeat steps 2-5
392
410
 
393
- The `process` command is ideally suited for a beanstalk job processing daemon.
411
+ The `process!` command is ideally suited for a beanstalk job processing daemon.
412
+ Even though `process!` is intended to be a long-running process, you can stop the loop at any time
413
+ by raising `AbortProcessingError` while processing is running.
394
414
 
395
415
  ### Handling Errors
396
416
 
@@ -409,7 +429,7 @@ are listed below:
409
429
  There are other exceptions that are less common such as `OutOfMemoryError`, `DrainingError`,
410
430
  `DeadlineSoonError`, `InternalError`, `BadFormatError`, `UnknownCommandError`,
411
431
  `ExpectedCRLFError`, `JobTooBigError`, `NotIgnoredError`. Be sure to check the
412
- [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.
413
433
 
414
434
 
415
435
  ### Stats
@@ -420,8 +440,9 @@ beanstalk overall:
420
440
  ```ruby
421
441
  # Get overall stats about the job processing that has occurred
422
442
  print @beanstalk.stats
423
- # => { 'current_connections': 1, 'current_jobs_buried': 0, ... }
424
- 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
425
446
  # => 1
426
447
  ```
427
448
 
@@ -441,7 +462,7 @@ print @beanstalk.jobs[some_job_id].stats
441
462
  # => {'age': 0, 'id': 2, 'state': 'reserved', 'tube': 'default', ... }
442
463
  ```
443
464
 
444
- 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
445
466
  more details about the stats commands.
446
467
 
447
468
  ## Resources
@@ -452,11 +473,14 @@ There are other resources helpful when learning about beanstalk:
452
473
  * [Beaneater on Rubygems](https://rubygems.org/gems/beaneater)
453
474
  * [Beanstalkd homepage](http://kr.github.com/beanstalkd/)
454
475
  * [beanstalk on github](https://github.com/kr/beanstalkd)
455
- * [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)
456
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
457
479
 
458
480
  ## Contributors
459
481
 
460
482
  - [Nico Taing](https://github.com/Nico-Taing) - Creator and co-maintainer
461
483
  - [Nathan Esquenazi](https://github.com/nesquena) - Contributor and co-maintainer
462
- - [Keith Rarick](https://github.com/kr) - Much code inspired and adapted from beanstalk-client
484
+ - [Keith Rarick](https://github.com/kr) - Much code inspired and adapted from beanstalk-client
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) }
@@ -19,7 +20,6 @@ Gem::Specification.new do |gem|
19
20
  gem.add_development_dependency 'minitest', "~> 4.1.0"
20
21
  gem.add_development_dependency 'rake'
21
22
  gem.add_development_dependency 'mocha'
22
- gem.add_development_dependency 'fakeweb'
23
23
  gem.add_development_dependency 'term-ansicolor'
24
24
  gem.add_development_dependency 'json'
25
25
  end
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,19 +65,21 @@ 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.lock
50
- if connection
51
- command = command.force_encoding('ASCII-8BIT') if command.respond_to?(:force_encoding)
52
- connection.write(command+"\r\n")
53
- parse_response(command, connection.gets)
54
- else # no connection
55
- raise NotConnected, "Connection to beanstalk '#{@host}:#{@port}' is closed!" unless 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
+
77
+ command = command.force_encoding('ASCII-8BIT') if command.respond_to?(:force_encoding)
78
+ connection.write(command.to_s + "\r\n")
79
+ res = connection.readline
80
+ parse_response(command, res)
81
+ end
56
82
  end
57
- ensure
58
- @mutex.unlock
59
83
  end
60
84
 
61
85
  # Close connection with beanstalkd server.
@@ -64,8 +88,10 @@ module Beaneater
64
88
  # @conn.close
65
89
  #
66
90
  def close
67
- @connection.close
68
- @connection = nil
91
+ if @connection
92
+ @connection.close
93
+ @connection = nil
94
+ end
69
95
  end
70
96
 
71
97
  # Returns string representation of job.
@@ -78,23 +104,30 @@ module Beaneater
78
104
  end
79
105
  alias :inspect :to_s
80
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
+
81
116
  protected
82
117
 
83
118
  # Establish a connection based on beanstalk address.
84
119
  #
85
120
  # @return [Net::TCPSocket] connection for specified address.
86
- # @raise [Beanstalk::NotConnected] Could not connect to specified beanstalkd instance.
121
+ # @raise [Beaneater::NotConnected] Could not connect to specified beanstalkd instance.
87
122
  # @example
88
123
  # establish_connection('localhost:3005')
89
124
  #
90
125
  def establish_connection
91
- @match = address.split(':')
92
- @host, @port = @match[0], Integer(@match[1] || DEFAULT_PORT)
93
- TCPSocket.new @host, @port
94
- rescue Errno::ECONNREFUSED => e
95
- raise NotConnected, "Could not connect to '#{@host}:#{@port}'"
96
- rescue Exception => ex
97
- 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
98
131
  end
99
132
 
100
133
  # Parses the response and returns the useful beanstalk response.
@@ -102,11 +135,11 @@ module Beaneater
102
135
  #
103
136
  # @param [String] cmd Beanstalk command transmitted
104
137
  # @param [String] res Telnet command response
105
- # @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`
106
139
  # @raise [Beaneater::UnexpectedResponse] Response from beanstalk command was an error status
107
140
  # @example
108
141
  # parse_response("delete 56", "DELETED 56\nFOO")
109
- # # => { :body => "FOO", :status => "DELETED", :id => 56, :connection => <Connection> }
142
+ # # => { :body => "FOO", :status => "DELETED", :id => 56 }
110
143
  #
111
144
  def parse_response(cmd, res)
112
145
  status = res.chomp
@@ -119,12 +152,12 @@ module Beaneater
119
152
  raw_body = connection.read(bytes_size)
120
153
  body = status == 'OK' ? YAML.load(raw_body) : config.job_parser.call(raw_body)
121
154
  crlf = connection.read(2) # \r\n
122
- raise ExpectedCRLFError if crlf != "\r\n"
155
+ raise ExpectedCrlfError.new('EXPECTED_CRLF', cmd) if crlf != "\r\n"
123
156
  end
124
157
  id = body_values[1]
125
- response = { :status => status, :body => body }
158
+ response = { :status => status }
126
159
  response[:id] = id if id
127
- response[:connection] = self
160
+ response[:body] = body if body
128
161
  response
129
162
  end
130
163
 
@@ -135,5 +168,77 @@ module Beaneater
135
168
  Beaneater.configuration
136
169
  end
137
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
+
237
+ # Raises an error to be triggered when the connection has failed
238
+ # @raise [Beaneater::NotConnected] Beanstalkd is no longer connected
239
+ def _raise_not_connected!
240
+ raise Beaneater::NotConnected, "Connection to beanstalk '#{@host}:#{@port}' is closed!"
241
+ end
242
+
138
243
  end # Connection
139
244
  end # Beaneater