gemerald_beanstalk 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +27 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +67 -0
- data/Rakefile +19 -0
- data/gemerald_beanstalk.gemspec +25 -0
- data/lib/gemerald_beanstalk.rb +10 -0
- data/lib/gemerald_beanstalk/beanstalk.rb +289 -0
- data/lib/gemerald_beanstalk/beanstalk_helper.rb +300 -0
- data/lib/gemerald_beanstalk/command.rb +365 -0
- data/lib/gemerald_beanstalk/connection.rb +170 -0
- data/lib/gemerald_beanstalk/job.rb +229 -0
- data/lib/gemerald_beanstalk/jobs.rb +39 -0
- data/lib/gemerald_beanstalk/server.rb +54 -0
- data/lib/gemerald_beanstalk/tube.rb +164 -0
- data/lib/gemerald_beanstalk/version.rb +3 -0
- data/test/beanstalk_integration_tests_test.rb +2 -0
- data/test/test_helper.rb +8 -0
- metadata +133 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- jruby-19mode
|
7
|
+
- rbx-19mode
|
8
|
+
|
9
|
+
before_script:
|
10
|
+
- bundle config
|
11
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || git clone https://github.com/beanstalkd/beaneater.git /tmp/beaneater'
|
12
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || BUNDLE_GEMFILE=/tmp/beaneater/Gemfile bundle install'
|
13
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || git clone https://github.com/nesquena/backburner.git /tmp/backburner'
|
14
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || BUNDLE_GEMFILE=/tmp/backburner/Gemfile bundle install'
|
15
|
+
|
16
|
+
script:
|
17
|
+
- rake test
|
18
|
+
- sudo sed -i 's/^\(127.0.0.1.*\)$/\1 coveralls.io/' /etc/hosts
|
19
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || rake start_gemerald_beanstalk_test_server &'
|
20
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || cd /tmp/beaneater'
|
21
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || BUNDLE_GEMFILE=/tmp/beaneater/Gemfile bundle exec rake test:full'
|
22
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || cd /tmp/backburner'
|
23
|
+
- '[ "$TRAVIS_RUBY_VERSION" = "jruby-19mode" ] && (exit 0) || BUNDLE_GEMFILE=/tmp/backburner/Gemfile bundle exec rake'
|
24
|
+
|
25
|
+
matrix:
|
26
|
+
allow_failures:
|
27
|
+
- rvm: jruby-19mode
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Freewrite.org
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# GemeraldBeanstalk
|
2
|
+
[![Build Status](https://travis-ci.org/gemeraldbeanstalk/gemerald_beanstalk.png?branch=master)](https://travis-ci.org/gemeraldbeanstalk/gemerald_beanstalk)
|
3
|
+
[![Coverage Status](https://coveralls.io/repos/gemeraldbeanstalk/gemerald_beanstalk/badge.png)](https://coveralls.io/r/gemeraldbeanstalk/gemerald_beanstalk)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/gemeraldbeanstalk/gemerald_beanstalk.png)](https://codeclimate.com/github/gemeraldbeanstalk/gemerald_beanstalk)
|
5
|
+
[![Dependency Status](https://gemnasium.com/gemeraldbeanstalk/gemerald_beanstalk.png)](https://gemnasium.com/gemeraldbeanstalk/gemerald_beanstalk)
|
6
|
+
|
7
|
+
|
8
|
+
GemeraldBeanstalk offers a Ruby implementation of beanstalkd for testing and other uses.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
GemeraldBeanstalk should work as a drop in replacement for beanstalkd. You can
|
13
|
+
start a server via GemeraldBeanstalk::Server.start:
|
14
|
+
```ruby
|
15
|
+
|
16
|
+
# Start a GemeraldBeanstalk bound to 0.0.0.0:11300
|
17
|
+
GemeraldBeanstalk::Server.start
|
18
|
+
|
19
|
+
# Customize server binding
|
20
|
+
GemeraldBeanstalk::Server.start('192.168.1.10', 11301)
|
21
|
+
```
|
22
|
+
|
23
|
+
GemeraldBeanstalk::Server.start returns an array containing the Thread the
|
24
|
+
server is running in and the server's GemeraldBeanstalk::Beanstalk instance.
|
25
|
+
|
26
|
+
The internals of GemeraldBeanstalk are undocumented at this point, with the
|
27
|
+
expectation being that it should be interacted with strictly via the [beanstalkd
|
28
|
+
protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md). This
|
29
|
+
will likely change in the future, allowing more programatic access directly to
|
30
|
+
the GemeraldBeanstalk::Beanstalk.
|
31
|
+
|
32
|
+
## Installation
|
33
|
+
|
34
|
+
Add this line to your application's Gemfile:
|
35
|
+
|
36
|
+
gem 'gemerald_beanstalk'
|
37
|
+
|
38
|
+
And then execute:
|
39
|
+
|
40
|
+
$ bundle
|
41
|
+
|
42
|
+
Or install it yourself as:
|
43
|
+
|
44
|
+
$ gem install gemerald_beanstalk
|
45
|
+
|
46
|
+
## Unbugs!
|
47
|
+
In the process of building GemeraldBeanstalk, a number of bugs and inconsistencies
|
48
|
+
with Beanstalkd protocol were discovered. Patches have been submitted to correct
|
49
|
+
the various bugs and inconsistencies, but they have not yet been merged into
|
50
|
+
beanstalkd.
|
51
|
+
|
52
|
+
It would be fairly tedious to reproduce the behavior of some of the bugs, and as
|
53
|
+
such, GemeraldBeanstalk doesn't suffer from them. This can be troubling when
|
54
|
+
you run tests that work against GemeraldBeanstalk, but then fail against an
|
55
|
+
actual beanstalkd server. Below are a list of those protocol issues that exist
|
56
|
+
with Beanstalk, but not with GemeraldBeanstalk.
|
57
|
+
* [Pause tube should check tube name valid](https://github.com/kr/beanstalkd/pull/217)
|
58
|
+
* [Can't ignore tube with name 200 chars long](https://github.com/kr/beanstalkd/issues/212)
|
59
|
+
* [Use of 200-char tube name causes INTERNAL_ERROR](https://github.com/kr/beanstalkd/issues/211)
|
60
|
+
|
61
|
+
## Contributing
|
62
|
+
|
63
|
+
1. Fork it
|
64
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
65
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
66
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
67
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'gemerald_beanstalk'
|
4
|
+
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
task :start_gemerald_beanstalk_test_server do
|
12
|
+
Thread.abort_on_exception = true
|
13
|
+
server_thread, beanstalk = GemeraldBeanstalk::Server.start(ENV['BIND_ADDRESS'], ENV['PORT'])
|
14
|
+
trap("SIGINT") { server_thread.kill }
|
15
|
+
puts "GemeraldBeanstalk listening on #{beanstalk.address}"
|
16
|
+
server_thread.join
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default => :test
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gemerald_beanstalk/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'gemerald_beanstalk'
|
8
|
+
spec.version = GemeraldBeanstalk::VERSION
|
9
|
+
spec.authors = ['Freewrite.org']
|
10
|
+
spec.email = ['dev@freewrite.org']
|
11
|
+
spec.description = %q{RubyGem implementation of beanstalkd}
|
12
|
+
spec.summary = %q{Gemerald Beanstalk offers a Ruby implementation of beanstalkd for testing and other uses.}
|
13
|
+
spec.homepage = 'https://github.com/gemeraldbeanstalk/gemerald_beanstalk'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'eventmachine'
|
22
|
+
spec.add_dependency 'thread_safe'
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'gemerald_beanstalk/version'
|
3
|
+
require 'thread_safe'
|
4
|
+
require 'gemerald_beanstalk/job'
|
5
|
+
require 'gemerald_beanstalk/beanstalk'
|
6
|
+
require 'gemerald_beanstalk/connection'
|
7
|
+
require 'gemerald_beanstalk/command'
|
8
|
+
require 'gemerald_beanstalk/jobs'
|
9
|
+
require 'gemerald_beanstalk/tube'
|
10
|
+
require 'gemerald_beanstalk/server'
|
@@ -0,0 +1,289 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'socket'
|
3
|
+
require 'gemerald_beanstalk/beanstalk_helper'
|
4
|
+
|
5
|
+
class GemeraldBeanstalk::Beanstalk
|
6
|
+
|
7
|
+
# contains functionality supporting core commands
|
8
|
+
include GemeraldBeanstalk::BeanstalkHelper
|
9
|
+
|
10
|
+
# Colon-separated host and port of the Server the Beanstalk instance is
|
11
|
+
# running on.
|
12
|
+
attr_reader :address
|
13
|
+
|
14
|
+
# The maximum size in bytes that a job can be. Jobs exceeding this threshold
|
15
|
+
# will result in JOB_TOO_BIG responses.
|
16
|
+
attr_reader :max_job_size
|
17
|
+
|
18
|
+
|
19
|
+
# Initializes a new Beanstalk instance with the given +address+ and
|
20
|
+
# +maximum_job_size+. +address+ is a string identifying the host and port
|
21
|
+
# that the Beanstalk instance is running on. +maximum_job_size+ is the
|
22
|
+
# maximum size in bytes that a job can be. Jobs exceeding this threshold will
|
23
|
+
# result in JOB_TOO_BIG responses.
|
24
|
+
#
|
25
|
+
# beanstalk = GemeraldBeanstalk::Beanstalk.new('localhost:11300')
|
26
|
+
def initialize(address, maximum_job_size = 2**16)
|
27
|
+
@max_job_size = maximum_job_size
|
28
|
+
@address = address
|
29
|
+
@connections = ThreadSafe::Array.new
|
30
|
+
@delayed = ThreadSafe::Array.new
|
31
|
+
@id = SecureRandom.base64(16)
|
32
|
+
@jobs = GemeraldBeanstalk::Jobs.new
|
33
|
+
@mutex = Mutex.new
|
34
|
+
@paused = ThreadSafe::Array.new
|
35
|
+
@reserved = ThreadSafe::Cache.new {|reserved, key| reserved[key] = [] }
|
36
|
+
@stats = ThreadSafe::Hash.new(0)
|
37
|
+
@tubes = ThreadSafe::Cache.new
|
38
|
+
@up_at = Time.now.to_f
|
39
|
+
|
40
|
+
tube('default', :create_if_missing)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def bury(connection, job_id, priority, *args)
|
47
|
+
adjust_stats_key(:'cmd-bury')
|
48
|
+
job = find_job(job_id, :only => JOB_RESERVED_STATES)
|
49
|
+
return NOT_FOUND if job.nil? || !job.bury(connection, priority)
|
50
|
+
|
51
|
+
@reserved[connection].delete(job)
|
52
|
+
return BURIED
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def delete(connection, job_id = nil, *args)
|
57
|
+
adjust_stats_key(:'cmd-delete')
|
58
|
+
job = find_job(job_id)
|
59
|
+
return NOT_FOUND if job.nil?
|
60
|
+
|
61
|
+
original_state = job.state
|
62
|
+
return NOT_FOUND unless job.delete(connection)
|
63
|
+
|
64
|
+
tube(job.tube_name).delete(job)
|
65
|
+
@jobs[job.id - 1] = nil
|
66
|
+
@reserved[connection].delete(job) if JOB_RESERVED_STATES.include?(original_state)
|
67
|
+
|
68
|
+
return DELETED
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def ignore(connection, tube_name)
|
73
|
+
adjust_stats_key(:'cmd-ignore')
|
74
|
+
return NOT_IGNORED if (watched_count = connection.ignore(tube_name)).nil?
|
75
|
+
tube = tube(tube_name)
|
76
|
+
tube.ignore unless tube.nil?
|
77
|
+
return "WATCHING #{watched_count}\r\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def kick(connection, limit, *args)
|
82
|
+
adjust_stats_key(:'cmd-kick')
|
83
|
+
limit = limit.to_i
|
84
|
+
kicked = 0
|
85
|
+
JOB_INACTIVE_STATES.each do |job_state|
|
86
|
+
# GTE to handle negative limits
|
87
|
+
break if kicked >= limit
|
88
|
+
until (job = tube(connection.tube_used).next_job(job_state, :peek)).nil?
|
89
|
+
kicked += 1 if job.kick
|
90
|
+
break if kicked == limit
|
91
|
+
end
|
92
|
+
break if kicked > 0
|
93
|
+
end
|
94
|
+
|
95
|
+
return "KICKED #{kicked}\r\n"
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def kick_job(connection, job_id = nil, *args)
|
100
|
+
job = find_job(job_id, :only => JOB_INACTIVE_STATES)
|
101
|
+
return (!job.nil? && job.kick) ? KICKED : NOT_FOUND
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def list_tubes(connection)
|
106
|
+
adjust_stats_key(:'cmd-list-tubes')
|
107
|
+
return tube_list(active_tubes.keys)
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
def list_tube_used(connection)
|
112
|
+
adjust_stats_key(:'cmd-list-tube-used')
|
113
|
+
return "USING #{connection.tube_used}\r\n"
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def list_tubes_watched(connection)
|
118
|
+
adjust_stats_key(:'cmd-list-tubes-watched')
|
119
|
+
return tube_list(connection.tubes_watched)
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def pause_tube(connection, tube_name, delay)
|
124
|
+
adjust_stats_key(:'cmd-paue-tube')
|
125
|
+
return NOT_FOUND if (tube = tube(tube_name)).nil?
|
126
|
+
tube.pause(delay.to_i % 2**32)
|
127
|
+
@paused << tube
|
128
|
+
return PAUSED
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def peek(connection, job_id = nil, *args)
|
133
|
+
adjust_stats_key(:'cmd-peek')
|
134
|
+
return peek_message(find_job(job_id))
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def peek_buried(connection)
|
139
|
+
return peek_by_state(connection, :buried)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def peek_delayed(connection)
|
144
|
+
return peek_by_state(connection, :delayed)
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
def peek_ready(connection)
|
149
|
+
return peek_by_state(connection, :ready)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def put(connection, priority, delay, ttr, bytes, body)
|
154
|
+
adjust_stats_key(:'cmd-put')
|
155
|
+
bytes = bytes.to_i
|
156
|
+
return JOB_TOO_BIG if bytes > @max_job_size
|
157
|
+
return EXPECTED_CRLF if body.slice!(-2, 2) != CRLF || body.length != bytes
|
158
|
+
|
159
|
+
job = nil
|
160
|
+
# Ensure job insertion order and ID
|
161
|
+
@mutex.synchronize do
|
162
|
+
job = GemeraldBeanstalk::Job.new(self, @jobs.next_id, connection.tube_used, priority, delay, ttr, bytes, body)
|
163
|
+
@jobs.enqueue(job)
|
164
|
+
tube(connection.tube_used).put(job)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Send async so client doesn't wait while we check if job can be immediately dispatched
|
168
|
+
connection.transmit("INSERTED #{job.id}\r\n")
|
169
|
+
|
170
|
+
connection.producer = true
|
171
|
+
|
172
|
+
case job.state
|
173
|
+
when :ready
|
174
|
+
honor_reservations(job)
|
175
|
+
when :delayed
|
176
|
+
@delayed << job
|
177
|
+
end
|
178
|
+
return nil
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def quit(connection)
|
183
|
+
disconnect(connection)
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def release(connection, job_id, priority, delay)
|
189
|
+
adjust_stats_key(:'cmd-release')
|
190
|
+
job = find_job(job_id, :only => JOB_RESERVED_STATES)
|
191
|
+
return NOT_FOUND if job.nil? || !job.release(connection, priority, delay)
|
192
|
+
|
193
|
+
@reserved[connection].delete(job)
|
194
|
+
@delayed << job if job.delayed?
|
195
|
+
return RELEASED
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
def reserve(connection, *args)
|
200
|
+
adjust_stats_key(:'cmd-reserve')
|
201
|
+
return BAD_FORMAT unless args.empty?
|
202
|
+
reserve_job(connection)
|
203
|
+
return nil
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def reserve_with_timeout(connection, timeout = 0, *args)
|
208
|
+
adjust_stats_key(:'cmd-reserve-with-timeout')
|
209
|
+
timeout = timeout.to_i
|
210
|
+
return nil if reserve_job(connection, timeout) || timeout != 0
|
211
|
+
connection.wait_timed_out
|
212
|
+
return TIMED_OUT
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
def stats(connection)
|
217
|
+
adjust_stats_key(:'cmd-stats')
|
218
|
+
stats = @jobs.counts_by_state.merge(stats_commands).merge({
|
219
|
+
'job-timeouts' => @stats[:'job-timeouts'],
|
220
|
+
'total-jobs' => @jobs.total_jobs,
|
221
|
+
'max-job-size' => @max_job_size,
|
222
|
+
'current-tubes' => active_tubes.length,
|
223
|
+
}).merge(stats_connections).merge({
|
224
|
+
'pid' => Process.pid,
|
225
|
+
'version' => GemeraldBeanstalk::VERSION,
|
226
|
+
'rusage-utime' => 0,
|
227
|
+
'rusage-stime' => 0,
|
228
|
+
'uptime' => uptime,
|
229
|
+
'binlog-oldest-index' => 0,
|
230
|
+
'binlog-current-index' => 0,
|
231
|
+
'binlog-records-migrated' => 0,
|
232
|
+
'binlog-records-written' => 0,
|
233
|
+
'binlog-max-size' => 10485760,
|
234
|
+
'id' => @id,
|
235
|
+
'hostname' => Socket.gethostname,
|
236
|
+
})
|
237
|
+
return yaml_response(stats.map{|stat, value| "#{stat}: #{value}" })
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
def stats_job(connection, job_id = nil, *args)
|
242
|
+
adjust_stats_key(:'cmd-stats-job')
|
243
|
+
job = find_job(job_id)
|
244
|
+
return NOT_FOUND if job.nil?
|
245
|
+
|
246
|
+
return yaml_response(job.stats.map{ |stat, value| "#{stat}: #{value}" })
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
def stats_tube(connection, tube_name)
|
251
|
+
adjust_stats_key(:'cmd-stats-tube')
|
252
|
+
return NOT_FOUND if (tube = tube(tube_name)).nil?
|
253
|
+
|
254
|
+
return yaml_response(tube.stats.map{ |stat, value| "#{stat}: #{value}" })
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
def touch(connection, job_id = nil, *args)
|
259
|
+
adjust_stats_key(:'cmd-touch')
|
260
|
+
job = find_job(job_id, :only => JOB_RESERVED_STATES)
|
261
|
+
return NOT_FOUND if job.nil? || !job.touch(connection)
|
262
|
+
|
263
|
+
return TOUCHED
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
def use(connection, tube_name)
|
268
|
+
adjust_stats_key(:'cmd-use')
|
269
|
+
tube(connection.tube_used).stop_use
|
270
|
+
tube(tube_name, :create_if_missing).use
|
271
|
+
connection.use(tube_name)
|
272
|
+
|
273
|
+
return "USING #{tube_name}\r\n"
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
def watch(connection, tube_name)
|
278
|
+
adjust_stats_key(:'cmd-watch')
|
279
|
+
if connection.tubes_watched.include?(tube_name)
|
280
|
+
watched_count = connection.tubes_watched.length
|
281
|
+
else
|
282
|
+
tube(tube_name, :create_if_missing).watch
|
283
|
+
watched_count = connection.watch(tube_name)
|
284
|
+
end
|
285
|
+
|
286
|
+
return "WATCHING #{watched_count}\r\n"
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|