bean_counter 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|