bean_counter 0.0.4 → 0.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 +7 -0
- data/.travis.yml +1 -0
- data/README.md +30 -4
- data/bean_counter.gemspec +1 -0
- data/lib/bean_counter.rb +1 -0
- data/lib/bean_counter/strategies/gemerald_beanstalk_strategy.rb +3 -0
- data/lib/bean_counter/strategies/gemerald_beanstalk_strategy/job.rb +73 -0
- data/lib/bean_counter/strategies/gemerald_beanstalk_strategy/strategy.rb +251 -0
- data/lib/bean_counter/strategies/gemerald_beanstalk_strategy/tube.rb +56 -0
- data/lib/bean_counter/strategies/stalk_climber_strategy.rb +1 -1
- data/lib/bean_counter/version.rb +1 -1
- data/test/test_helper.rb +23 -0
- data/test/unit/strategies/gemerald_beanstalk_strategy/job_test.rb +86 -0
- data/test/unit/strategies/gemerald_beanstalk_strategy/tube_test.rb +103 -0
- data/test/unit/strategies/gemerald_beanstalk_strategy_test.rb +604 -0
- data/test/unit/strategies/stalk_climber_strategy_test.rb +14 -1
- metadata +44 -32
- data/.rspec +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e093642cbffceb8f4714bc9f8fece7a8dd7c44c4
|
4
|
+
data.tar.gz: 49f7dc68b35365ebca7d40544936a8b6a8a3a23b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28d291b01222cbe8b50158f4ec55a1cdb836bbda6abd3c7a3b65b8222e2fd005af07232982b363fe9a7c405a9a23472f2e62a965a76029575ff4f731582311f8
|
7
|
+
data.tar.gz: 60bc42d02c66e50642faf210b897ec977d0bff9d279655b6286fa6ae24c4bd5f873c3cb3840badb746d5c6c588f1fc6d8ab92c1c2d4daff3948ed0814127e18f
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -172,16 +172,42 @@ BeanCounter.beanstalkd_url
|
|
172
172
|
###BeanCounter.strategy
|
173
173
|
`BeanCounter.strategy` allows you to choose and configure the strategy
|
174
174
|
BeanCounter uses for accessing and interacting with the beanstalkd pool. At
|
175
|
-
present, there
|
176
|
-
|
175
|
+
present, there are two strategies available: StalkClimberStrategy and
|
176
|
+
GemeraldBeanstalkStrategy.
|
177
177
|
|
178
|
-
The
|
178
|
+
The default BeanCounter::Strategy::StalkClimber strategy utilizes
|
179
179
|
[StalkClimber](https://github.com/gemeraldbeanstalk/stalk_climber.git) to
|
180
180
|
navigate the beanstalkd pool. The job traversal method employed by StalkClimber
|
181
181
|
suffers from some inefficiencies that come with trying to sequential access a
|
182
182
|
queue, but overall it is a powerful strategy that supports multiple servers and
|
183
183
|
offers solid performance given the design of beanstalkd.
|
184
184
|
|
185
|
+
The BeanCounter::Strategy::GemeraldBeanstalkStrategy strategy utilizes
|
186
|
+
[GemeraldBeanstalk](https://github.com/gemeraldbeanstalk/gemerald_beanstalk.git)
|
187
|
+
servers as the backend for Beaneater. This means that no beanstalkd server is
|
188
|
+
required for testing. Beaneater still connects and communicates with
|
189
|
+
GemeraldBeanstalk via a TCPSocket, however BeanCounter is able to talk directly
|
190
|
+
to the GemeraldBeanstalk servers allowing for faster and more consistent testing.
|
191
|
+
When using the GemeraldBeanstalkStrategy, BeanCounter will automatically start
|
192
|
+
a GemeraldBeanstalk server at each of the addresses specified by beanstalkd_url.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# No configuration is required to use the StalkClimberStrategy
|
196
|
+
|
197
|
+
# To use the GemeraldBeanstalkStrategy
|
198
|
+
BeanCounter.strategy = :'BeanCounter::Strategy::GemeraldBeanstalkStrategy'
|
199
|
+
#=> :"BeanCounter::Strategy::GemeraldBeanstalkStrategy"
|
200
|
+
|
201
|
+
# Because the GemeraldBeanstalkStrategy starts a GemeraldBeanstalk server
|
202
|
+
# immediately, you may want to configure a different address/port for
|
203
|
+
# your GemeraldBeanstalk servers to avoid conflicts when you have a Beanstalkd
|
204
|
+
# server running:
|
205
|
+
BeanCounter.beanstalkd_url = ['127.0.0.1:11400']
|
206
|
+
BeanCounter.strategy = :'BeanCounter::Strategy::GemeraldBeanstalkStrategy'
|
207
|
+
#=> :"BeanCounter::Strategy::GemeraldBeanstalkStrategy"
|
208
|
+
```
|
209
|
+
|
210
|
+
|
185
211
|
## Usage
|
186
212
|
Whether you are using the TestUnit/MiniTest or RSpec matchers, the usage is the
|
187
213
|
same, the only difference is the invocation.
|
@@ -312,7 +338,7 @@ verify that the exports tube is paused:
|
|
312
338
|
For more detailed explanations and more examples make sure to check out the
|
313
339
|
docs, expectations, and respective tests:
|
314
340
|
|
315
|
-
- [docs](http://rubydoc.info/gems/bean_counter/0.0
|
341
|
+
- [docs](http://rubydoc.info/gems/bean_counter/0.1.0/frames)
|
316
342
|
- [enqueued_expectation](https://github.com/gemeraldbeanstalk/bean_counter/tree/master/lib/bean_counter/enqueued_expectation.rb)
|
317
343
|
- [tube_expectation](https://github.com/gemeraldbeanstalk/bean_counter/tree/master/lib/bean_counter/tube_expectation.rb)
|
318
344
|
- [test_assertions](https://github.com/gemeraldbeanstalk/bean_counter/tree/master/lib/bean_counter/test_assertions.rb)
|
data/bean_counter.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency 'beaneater'
|
22
22
|
spec.add_dependency 'stalk_climber', '>= 0.1.0'
|
23
|
+
spec.add_dependency 'gemerald_beanstalk', '>= 0.0.1'
|
23
24
|
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
26
|
spec.add_development_dependency 'rake'
|
data/lib/bean_counter.rb
CHANGED
@@ -4,5 +4,6 @@ require 'bean_counter/version'
|
|
4
4
|
require 'bean_counter/core'
|
5
5
|
require 'bean_counter/strategy'
|
6
6
|
require 'bean_counter/strategies/stalk_climber_strategy'
|
7
|
+
require 'bean_counter/strategies/gemerald_beanstalk_strategy'
|
7
8
|
require 'bean_counter/enqueued_expectation'
|
8
9
|
require 'bean_counter/tube_expectation'
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
class BeanCounter::Strategy::GemeraldBeanstalkStrategy::Job
|
4
|
+
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@gemerald_job, :body, :stats
|
8
|
+
|
9
|
+
attr_reader :connection
|
10
|
+
|
11
|
+
# Attributes that should be retrieved via the gemerald job's stats. This
|
12
|
+
# list is used to dynamically create the appropriate accessor methods
|
13
|
+
STATS_METHODS = %w[
|
14
|
+
age buries delay id kicks pri releases reserves
|
15
|
+
state time-left timeouts ttr tube
|
16
|
+
]
|
17
|
+
|
18
|
+
# Simple accessors allowing direct access to job stats attributes
|
19
|
+
STATS_METHODS.each do |stat_method|
|
20
|
+
define_method stat_method.gsub(/-/, '_') do
|
21
|
+
return @gemerald_job.stats[stat_method]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Attempts to delete the job. Returns true if deletion succeeds or if job
|
27
|
+
# does not exist. Returns false if job could not be deleted (typically due
|
28
|
+
# to it being reserved by another connection).
|
29
|
+
#
|
30
|
+
# @return [Boolean] If the given job was successfully deleted or does not
|
31
|
+
# exist, returns true. Otherwise returns false.
|
32
|
+
def delete
|
33
|
+
response = connection.transmit("delete #{id}")
|
34
|
+
if response == "DELETED\r\n" || !exists?
|
35
|
+
return true
|
36
|
+
else
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Returns a Boolean indicating whether or not the job still exists.
|
43
|
+
# @return [Boolean] If job state is deleted or the job does not exist
|
44
|
+
# on the beanstalk server, returns false. If job state is not deleted,
|
45
|
+
# returns true if the job exists on the beanstalk server.
|
46
|
+
def exists?
|
47
|
+
return false if state == 'deleted'
|
48
|
+
return connection.transmit("stats-job #{id}") != "NOT_FOUND\r\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Initialize a new GemeraldBeanstalkStrategy::Job wrapping the provided
|
53
|
+
# `gemerald_job` in the context of the provided `connection`.
|
54
|
+
def initialize(gemerald_job, connection)
|
55
|
+
@gemerald_job = gemerald_job
|
56
|
+
@connection = connection
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Augment job stats to provide a Hash representation of the job.
|
61
|
+
# @return [Hash] Hash representation of the job
|
62
|
+
def to_hash
|
63
|
+
stats_pairs = stats.to_a
|
64
|
+
stats_pairs << ['body', body]
|
65
|
+
stats_pairs << ['connection', connection]
|
66
|
+
|
67
|
+
hash = Hash[stats_pairs.sort_by!(&:first)]
|
68
|
+
hash.delete('file')
|
69
|
+
|
70
|
+
return hash
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'gemerald_beanstalk'
|
2
|
+
require 'gemerald_beanstalk/plugins/introspection'
|
3
|
+
require 'gemerald_beanstalk/plugins/direct_connection'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
class BeanCounter::Strategy::GemeraldBeanstalkStrategy < BeanCounter::Strategy
|
7
|
+
|
8
|
+
# Regex for checking for valid V4 IP addresses
|
9
|
+
V4_IP_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?::\d+)?$/
|
10
|
+
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def_delegator :job_enumerator, :each, :jobs
|
14
|
+
def_delegator :tube_enumerator, :each, :tubes
|
15
|
+
|
16
|
+
|
17
|
+
# Collects all jobs enqueued during the execution of the provided `block`.
|
18
|
+
# Returns an Array of GemeraldBeanstalkStrategy::Job.
|
19
|
+
#
|
20
|
+
# Fulfills {BeanCounter::Strategy#collect_new_jobs} contract.
|
21
|
+
#
|
22
|
+
# @see BeanCounter::Strategy#collect_new_jobs
|
23
|
+
# @see BeanCounter::Strategy::GemeraldBeanstalkStrategy::Job
|
24
|
+
# @yield Nothing is yielded to the provided `block`
|
25
|
+
# @raise [ArgumentError] if a block is not provided.
|
26
|
+
# @return [Array<GemeraldBeanstalkStrategy::Job>] all jobs enqueued during the
|
27
|
+
# execution of the provided `block`
|
28
|
+
def collect_new_jobs
|
29
|
+
raise ArgumentError, 'Block required' unless block_given?
|
30
|
+
|
31
|
+
max_id_pairs = beanstalks.map do |beanstalk|
|
32
|
+
[beanstalk, beanstalk.jobs[-1] ? beanstalk.jobs[-1].id : 0]
|
33
|
+
end
|
34
|
+
max_ids = Hash[max_id_pairs]
|
35
|
+
|
36
|
+
yield
|
37
|
+
|
38
|
+
new_jobs = []
|
39
|
+
# Jobs are collected in reverse, so iterate beanstalks in reverse too
|
40
|
+
beanstalks.reverse.each do |beanstalk|
|
41
|
+
jobs = beanstalk.jobs
|
42
|
+
index = -1
|
43
|
+
while (job = jobs[index]) && job.id > max_ids[beanstalk] do
|
44
|
+
new_jobs << strategy_job(job)
|
45
|
+
index -= 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# Flip new jobs to maintain beanstalk, id asc order
|
49
|
+
return new_jobs.reverse
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Attempts to delete the provided GemeraldBeanstalkStrategy::Job `job`.
|
54
|
+
# Returns true if deletion succeeds or if `job` does not exist. Returns false
|
55
|
+
# if `job` could not be deleted (typically due to it being reserved by
|
56
|
+
# another connection).
|
57
|
+
#
|
58
|
+
# Fulfills {BeanCounter::Strategy#delete_job} contract.
|
59
|
+
#
|
60
|
+
# @see BeanCounter::Strategy#delete_job
|
61
|
+
# @param job [GemeraldBeanstalkStrategy::Job] the job to be deleted
|
62
|
+
# @return [Boolean] If the given job was successfully deleted or does not
|
63
|
+
# exist, returns true. Otherwise returns false.
|
64
|
+
def delete_job(job)
|
65
|
+
return job.delete
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Initialize a new GemeraldBeanstalkStrategy. This includes initializing
|
70
|
+
# GemeraldBeanstalk::Servers for each of the beanstalk_urls visible to
|
71
|
+
# BeanCounter and also spawning direct connections to those servers.
|
72
|
+
def initialize
|
73
|
+
@clients = {}
|
74
|
+
@beanstalk_servers = []
|
75
|
+
BeanCounter.beanstalkd_url.each do |url|
|
76
|
+
server = GemeraldBeanstalk::Server.new(*parse_url(url))
|
77
|
+
@clients[server.beanstalk] = server.beanstalk.direct_connection_client
|
78
|
+
@beanstalk_servers << server
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Returns a Boolean indicating whether or not the provided
|
84
|
+
# GemeraldBeanstalkStrategy::Job `job` matches the given Hash of `options`.
|
85
|
+
#
|
86
|
+
# See {MATCHABLE_JOB_ATTRIBUTES} for a list of
|
87
|
+
# attributes that can be used when matching.
|
88
|
+
#
|
89
|
+
# Fulfills {BeanCounter::Strategy#job_matches?} contract.
|
90
|
+
#
|
91
|
+
# @see MATCHABLE_JOB_ATTRIBUTES
|
92
|
+
# @see BeanCounter::Strategy#job_matches?
|
93
|
+
# @param job [GemeraldBeanstalkStrategy::Job] the job to evaluate for a matche.
|
94
|
+
# @param options
|
95
|
+
# [Hash{String, Symbol => Numeric, Proc, Range, Regexp, String, Symbol}]
|
96
|
+
# Options to be used to evaluate a match.
|
97
|
+
# @return [Boolean] If job exists and matches the provided options, returns
|
98
|
+
# true. Otherwise, returns false.
|
99
|
+
def job_matches?(job, options = {})
|
100
|
+
return matcher(MATCHABLE_JOB_ATTRIBUTES, job, options)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# Returns a String representation of the GemeraldBeanstalkStrategy::Job `job`
|
105
|
+
# in a pretty, human readable format.
|
106
|
+
#
|
107
|
+
# Fulfills {BeanCounter::Strategy#pretty_print_job} contract.
|
108
|
+
#
|
109
|
+
# @see BeanCounter::Strategy#pretty_print_job
|
110
|
+
# @param job [GemeraldBeanstalkStrategy::Job] the job to print in a more
|
111
|
+
# readable format.
|
112
|
+
# @return [String] A more human-readable representation of `job`.
|
113
|
+
def pretty_print_job(job)
|
114
|
+
hash = job.to_hash
|
115
|
+
hash.delete('connection')
|
116
|
+
return hash.to_s
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# Returns a String representation of `tube` in a pretty, human readable format.
|
121
|
+
#
|
122
|
+
# Fulfills {BeanCounter::Strategy#pretty_print_tube} contract.
|
123
|
+
#
|
124
|
+
# @see BeanCounter::Strategy#pretty_print_tube
|
125
|
+
# @param tube [GemeraldBeanstalkStrategy::Tube] the tube to print in a more
|
126
|
+
# readable format.
|
127
|
+
# @return [String] A more human-readable representation of `tube`.
|
128
|
+
def pretty_print_tube(tube)
|
129
|
+
return tube.to_hash.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
# Returns a boolean indicating whether or not the provided
|
134
|
+
# GemeraldBeanstalkStrategy::Tube, `tube`, matches the given Hash of `options`.
|
135
|
+
#
|
136
|
+
# See {MATCHABLE_TUBE_ATTRIBUTES} for a list of attributes that can be used
|
137
|
+
# when evaluating a match.
|
138
|
+
#
|
139
|
+
# Fulfills {BeanCounter::Strategy#tube_matches?} contract.
|
140
|
+
#
|
141
|
+
# @see BeanCounter::Strategy#tube_matches?
|
142
|
+
# @param tube [GemeraldBeanstalkStrategy::Tube] the tube to evaluate a match
|
143
|
+
# against.
|
144
|
+
# @param options
|
145
|
+
# [Hash{String, Symbol => Numeric, Proc, Range, Regexp, String, Symbol}]
|
146
|
+
# a Hash of options to use when evaluating a match.
|
147
|
+
# @return [Boolean] If `tube` exists and matches against the provided options,
|
148
|
+
# returns true. Otherwise returns false.
|
149
|
+
def tube_matches?(tube, options = {})
|
150
|
+
return false if tube.nil?
|
151
|
+
return matcher(MATCHABLE_TUBE_ATTRIBUTES, tube, options)
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
# The collection of GemeraldBeanstalk servers the strategy built during
|
157
|
+
# initialization
|
158
|
+
attr_reader :beanstalk_servers
|
159
|
+
|
160
|
+
|
161
|
+
# The collection of beanstalks belonginging to the GemeraldBeanstalk servers
|
162
|
+
# that were created during initialization.
|
163
|
+
#
|
164
|
+
# @return [Array<GemeraldBeanstalk::Beanstalk>] the Beanstalks of the
|
165
|
+
# GemeraldBeanstalk::Servers
|
166
|
+
def beanstalks
|
167
|
+
return @beanstalks ||= @beanstalk_servers.map(&:beanstalk)
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# Returns an enumerator that enumerates all jobs on all beanstalk servers in
|
172
|
+
# the order the beanstalk servers are defined in ascending order. Jobs are
|
173
|
+
# returned as GemeraldBeanstalkStrategy::Job.
|
174
|
+
def job_enumerator
|
175
|
+
return Enumerator.new do |yielder|
|
176
|
+
beanstalks.each do |beanstalk|
|
177
|
+
beanstalk.jobs.each do |job|
|
178
|
+
yielder << strategy_job(job)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
# Generic match evaluator that compares the Hash of `options` given to the
|
186
|
+
# Strategy representation of the given `matchable`.
|
187
|
+
def matcher(valid_attributes, matchable, options = {})
|
188
|
+
return false unless matchable.exists?
|
189
|
+
return (options.keys & valid_attributes).all? do |key|
|
190
|
+
options[key] === matchable.send(key.to_s.gsub(/-/, '_'))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
# Parses a variety of forms of beanstalk URL and returns a pair including the
|
196
|
+
# hostname and possibly a port given by the url.
|
197
|
+
def parse_url(url)
|
198
|
+
unless V4_IP_REGEX === url
|
199
|
+
uri = URI.parse(url)
|
200
|
+
if uri.scheme && uri.host
|
201
|
+
raise(ArgumentError, "Invalid beanstalk URI: #{url}") unless uri.scheme == 'beanstalk'
|
202
|
+
host = uri.host
|
203
|
+
port = uri.port
|
204
|
+
end
|
205
|
+
end
|
206
|
+
unless host
|
207
|
+
match = url.split(/:/)
|
208
|
+
host = match[0]
|
209
|
+
port = match[1]
|
210
|
+
end
|
211
|
+
return port ? [host, Integer(port)] : [host]
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
# Helper method to transform a GemeraldBeanstalk::Job into a
|
216
|
+
# BeanCounter::Strategy::GemeraldBeanstalkStrategy::Job. The strategy
|
217
|
+
# specific job class is intended to hide native job implementation interface
|
218
|
+
# specifics and prevent meddling with native Job internals.
|
219
|
+
def strategy_job(gemerald_job)
|
220
|
+
return BeanCounter::Strategy::GemeraldBeanstalkStrategy::Job.new(gemerald_job, @clients[gemerald_job.beanstalk])
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
# Helper method to transform a `tube_name` into a
|
225
|
+
# BeanCounter::Strategy::GemeraldBeanstalkStrategy::Tube. The strategy
|
226
|
+
# specific tube class is intended to hide native tube implementation interface
|
227
|
+
# specifics and prevent meddling with native Tube internals. Also handles
|
228
|
+
# merging of tube data from multiple servers, as such, requires access to
|
229
|
+
# beanstalk servers.
|
230
|
+
def strategy_tube(tube_name)
|
231
|
+
return BeanCounter::Strategy::GemeraldBeanstalkStrategy::Tube.new(tube_name, beanstalks)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
# Returns an enumerator that enumerates all tubes on all beanstalk servers.
|
236
|
+
# Each tube is included in the enumeration only once, regardless of how many
|
237
|
+
# servers contain an instance of that tube. Tube stats are merged before they
|
238
|
+
# are yielded by the enumerator as a GemeraldBeanstalkdStrategy::Tube.
|
239
|
+
def tube_enumerator
|
240
|
+
tubes_in_pool = beanstalks.inject([]) do |memo, beanstalk|
|
241
|
+
memo.concat(beanstalk.tubes.keys)
|
242
|
+
end
|
243
|
+
tubes_in_pool.uniq!
|
244
|
+
return Enumerator.new do |yielder|
|
245
|
+
tubes_in_pool.each do |tube_name|
|
246
|
+
yielder << strategy_tube(tube_name)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class BeanCounter::Strategy::GemeraldBeanstalkStrategy::Tube
|
2
|
+
|
3
|
+
# The name of the tube represented by the object
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
# Attributes that should be obtained via the tube's stats. This list is used
|
7
|
+
# to dynamically create the attribute accessor methods.
|
8
|
+
STATS_METHODS = %w[
|
9
|
+
cmd-delete cmd-pause-tube current-jobs-buried current-jobs-delayed
|
10
|
+
current-jobs-ready current-jobs-reserved current-jobs-urgent current-using
|
11
|
+
current-waiting current-watching pause pause-time-left total-jobs
|
12
|
+
]
|
13
|
+
|
14
|
+
STATS_METHODS.each do |attr_method|
|
15
|
+
define_method attr_method.gsub(/-/, '_') do
|
16
|
+
return to_hash[attr_method]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a Boolean indicating whether or not the tube exists in the pool.
|
21
|
+
# @return [Boolean] Returns true if tube exists on any of the servers in the
|
22
|
+
# pool, otherwise returns false.
|
23
|
+
def exists?
|
24
|
+
tubes_in_pool = @beanstalks.inject([]) do |memo, beanstalk|
|
25
|
+
memo.concat(beanstalk.tubes.keys)
|
26
|
+
end
|
27
|
+
tubes_in_pool.uniq!
|
28
|
+
return tubes_in_pool.include?(@name)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Initialize a new GemeraldBeanstalkStrategy::Tube representing all tubes
|
33
|
+
# named `tube_name` in the given pool of `beanstalks`.
|
34
|
+
def initialize(tube_name, beanstalks)
|
35
|
+
@name = tube_name
|
36
|
+
@beanstalks = beanstalks
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Retrieves stats for the given `tube_name` from all known servers and merges
|
41
|
+
# numeric stats. Matches Beaneater's treatment of a tube as a collective
|
42
|
+
# entity and not a per-server entity.
|
43
|
+
def to_hash
|
44
|
+
return @beanstalks.inject({}) do |hash, beanstalk|
|
45
|
+
next hash if (tube = beanstalk.tubes[name]).nil?
|
46
|
+
next tube.stats if hash.empty?
|
47
|
+
|
48
|
+
tube.stats.each do |stat, value|
|
49
|
+
next unless value.is_a?(Numeric)
|
50
|
+
hash[stat] += value
|
51
|
+
end
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|