beaneater 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +14 -0
- data/README.md +56 -14
- data/Rakefile +8 -0
- data/TODO +0 -1
- data/lib/beaneater/connection.rb +26 -16
- data/lib/beaneater/errors.rb +5 -2
- data/lib/beaneater/job/collection.rb +30 -16
- data/lib/beaneater/job/record.rb +61 -23
- data/lib/beaneater/pool.rb +59 -34
- data/lib/beaneater/pool_command.rb +20 -12
- data/lib/beaneater/stats/stat_struct.rb +2 -2
- data/lib/beaneater/stats.rb +1 -0
- data/lib/beaneater/tube/collection.rb +24 -16
- data/lib/beaneater/tube/record.rb +8 -4
- data/lib/beaneater/version.rb +1 -1
- data/lib/beaneater.rb +1 -2
- data/test/beaneater_test.rb +1 -0
- data/test/job_test.rb +38 -0
- data/test/jobs_test.rb +24 -0
- data/test/pool_command_test.rb +27 -5
- data/test/stats_test.rb +2 -1
- metadata +3 -9
- data/REF +0 -23
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# CHANGELOG for Beaneater
|
2
|
+
|
3
|
+
## 0.1.2 (Unreleased)
|
4
|
+
|
5
|
+
## 0.1.1 (Nov 4 2012)
|
6
|
+
|
7
|
+
* Add `Jobs#find_all` to fix #10
|
8
|
+
* Fixed issue with `tubes-list` by merging results
|
9
|
+
* Add `Job#ttr`, `Job#pri`, `Job#delay`
|
10
|
+
* Improved yardocs coverage and accuracy
|
11
|
+
|
12
|
+
## 0.1.0 (Nov 1 2012)
|
13
|
+
|
14
|
+
* Initial release!
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Beaneater is the best way to interact with beanstalkd from within Ruby.
|
4
4
|
[Beanstalkd](http://kr.github.com/beanstalkd/) is a simple, fast work queue. Its interface is generic, but was
|
5
5
|
originally designed for reducing the latency of page views in high-volume web applications by
|
6
|
-
running time-consuming tasks asynchronously. Read the
|
6
|
+
running time-consuming tasks asynchronously. Read the [yardocs](http://rdoc.info/github/beanstalkd/beaneater) and/or the
|
7
7
|
[beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md) for more details.
|
8
8
|
|
9
9
|
|
@@ -13,32 +13,35 @@ Illya has an excellent blog post
|
|
13
13
|
[Scalable Work Queues with Beanstalk](http://www.igvita.com/2010/05/20/scalable-work-queues-with-beanstalk/) and
|
14
14
|
Adam Wiggins posted [an excellent comparison](http://adam.heroku.com/past/2010/4/24/beanstalk_a_simple_and_fast_queueing_backend/).
|
15
15
|
|
16
|
-
You will
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
You will find that **beanstalkd** is an underrated but incredibly
|
17
|
+
powerful project that is extremely well-suited as a job or messaging queue.
|
18
|
+
Significantly better suited for this task than Redis or a traditional RDBMS. Beanstalk is a simple,
|
19
|
+
and fast work queue service rolled into a single binary - it is the memcached of work queues.
|
20
|
+
Originally built to power the backend for the 'Causes' Facebook app,
|
21
|
+
it is a mature and production ready open source project.
|
22
|
+
[PostRank](http://www.postrank.com) has used beanstalk to reliably process millions of jobs a day.
|
21
23
|
|
22
24
|
A single instance of Beanstalk is perfectly capable of handling thousands of jobs a second (or more, depending on your job size)
|
23
25
|
because it is an in-memory, event-driven system. Powered by libevent under the hood,
|
24
|
-
it requires zero setup (launch and forget, à la memcached), optional log based persistence,
|
25
|
-
and a rich set of tools for job management
|
26
|
+
it requires zero setup (launch and forget, à la memcached), optional log based persistence,
|
27
|
+
an easily parsed ASCII protocol, and a rich set of tools for job management
|
28
|
+
that go well beyond a simple FIFO work queue.
|
26
29
|
|
27
30
|
Beanstalkd supports the following features out of the box:
|
28
31
|
|
29
32
|
| Feature | Description |
|
30
33
|
| ------- | ------------------------------- |
|
31
|
-
| **
|
34
|
+
| **Parallelized** | Supports multiple work queues created on demand. |
|
32
35
|
| **Reliable** | Beanstalk’s reserve, work, delete cycle ensures reliable processing. |
|
33
36
|
| **Scheduling** | Delay enqueuing jobs by a specified interval to schedule processing later |
|
34
|
-
| **Fast** | Processes thousands of jobs per second
|
37
|
+
| **Fast** | Processes thousands of jobs per second without breaking a sweat. |
|
35
38
|
| **Priorities** | Specify priority so important jobs can be processed quickly. |
|
36
39
|
| **Persistence** | Jobs are stored in memory for speed, but logged to disk for safe keeping. |
|
37
40
|
| **Federation** | Horizontal scalability provided through federation by the client. |
|
38
41
|
| **Error Handling** | Bury any job which causes an error for later debugging and inspection.|
|
39
42
|
|
40
|
-
Keep in mind that these features are supported out of the box with beanstalk and
|
41
|
-
In the end, **beanstalk is the ideal job queue**
|
43
|
+
Keep in mind that these features are supported out of the box with beanstalk and requires no special ruby specific logic.
|
44
|
+
In the end, **beanstalk is the ideal job queue** and has the added benefit of being easy to setup and configure.
|
42
45
|
|
43
46
|
## Installation
|
44
47
|
|
@@ -47,7 +50,6 @@ Install beanstalkd:
|
|
47
50
|
Mac OS
|
48
51
|
|
49
52
|
```
|
50
|
-
brew update
|
51
53
|
brew install beanstalkd
|
52
54
|
beanstalkd -p 11300
|
53
55
|
```
|
@@ -74,6 +76,29 @@ gem 'beaneater'
|
|
74
76
|
|
75
77
|
and run `bundle install` to install the dependency.
|
76
78
|
|
79
|
+
## Quick Overview:
|
80
|
+
|
81
|
+
The concise summary of how to use beaneater:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# Connect to pool
|
85
|
+
@beanstalk = Beaneater::Pool.new(['localhost:11300'])
|
86
|
+
# Enqueue jobs to tube
|
87
|
+
@tube = @beanstalk.tubes["my-tube"]
|
88
|
+
@tube.put '{ "key" : "foo" }', :pri => 5
|
89
|
+
@tube.put '{ "key" : "bar" }', :delay => 3
|
90
|
+
# Process jobs from tube
|
91
|
+
while @tube.peek(:ready)
|
92
|
+
job = @tube.reserve
|
93
|
+
puts "job value is #{job.body["key"]}!"
|
94
|
+
job.delete
|
95
|
+
end
|
96
|
+
# Disconnect the pool
|
97
|
+
@beanstalk.close
|
98
|
+
```
|
99
|
+
|
100
|
+
For a more detailed rundown, check out the __Usage__ section below.
|
101
|
+
|
77
102
|
## Usage
|
78
103
|
|
79
104
|
### Connection
|
@@ -82,6 +107,11 @@ To interact with a beanstalk queue, first establish a connection by providing a
|
|
82
107
|
|
83
108
|
```ruby
|
84
109
|
@beanstalk = Beaneater::Pool.new(['10.0.1.5:11300'])
|
110
|
+
|
111
|
+
# Or if ENV['BEANSTALKD_URL] == 'localhost:11300,127.0.0.1:11300'
|
112
|
+
@beanstalk = Beaneater::Pool.new
|
113
|
+
@beanstalk.connections.first # => localhost:11300
|
114
|
+
@beanstalk.connections.last # => 127.0.0.1:11300
|
85
115
|
```
|
86
116
|
|
87
117
|
You can conversely close and dispose of a pool at any time with:
|
@@ -277,6 +307,13 @@ inspected using the 'peek' commands. To find and peek at a particular job based
|
|
277
307
|
# => <Beaneater::Job id=123 body="foo">
|
278
308
|
```
|
279
309
|
|
310
|
+
You can also `find_all` jobs across all connections:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
@beanstalk.jobs.find_all(123)
|
314
|
+
# => [<Beaneater::Job id=123 body="foo">, <Beaneater::Job id=123 body="bar">]
|
315
|
+
```
|
316
|
+
|
280
317
|
or you can peek at jobs within a tube:
|
281
318
|
|
282
319
|
```ruby
|
@@ -346,6 +383,7 @@ are listed below:
|
|
346
383
|
| Beaneater::InvalidTubeName | Specified tube name for use or watch is not valid. |
|
347
384
|
| Beaneater::NotFoundError | Specified job or tube could not be found. |
|
348
385
|
| Beaneater::TimedOutError | Job could not be reserved within time specified. |
|
386
|
+
| Beaneater::JobNotReserved | Job has not been reserved and action cannot be taken. |
|
349
387
|
|
350
388
|
There are other exceptions that are less common such as `OutOfMemoryError`, `DrainingError`,
|
351
389
|
`DeadlineSoonError`, `InternalError`, `BadFormatError`, `UnknownCommandError`,
|
@@ -389,11 +427,15 @@ more details about the stats commands.
|
|
389
427
|
|
390
428
|
There are other resources helpful when learning about beanstalk:
|
391
429
|
|
430
|
+
* [Beaneater Yardocs](http://rdoc.info/github/beanstalkd/beaneater)
|
431
|
+
* [Beaneater on Rubygems](https://rubygems.org/gems/beaneater)
|
392
432
|
* [Beanstalkd homepage](http://kr.github.com/beanstalkd/)
|
393
433
|
* [beanstalk on github](https://github.com/kr/beanstalkd)
|
394
434
|
* [beanstalk protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md)
|
435
|
+
* [Backburner](https://github.com/nesquena/backburner) - Ruby job queue for Rails/Sinatra
|
395
436
|
|
396
437
|
## Contributors
|
397
438
|
|
398
439
|
- [Nico Taing](https://github.com/Nico-Taing) - Creator and co-maintainer
|
399
|
-
- [Nathan Esquenazi](https://github.com/nesquena) - Contributor and co-maintainer
|
440
|
+
- [Nathan Esquenazi](https://github.com/nesquena) - Contributor and co-maintainer
|
441
|
+
- [Keith Rarick](https://github.com/kr) - Much code inspired and adapted from beanstalk-client
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@ require 'rake/testtask'
|
|
3
3
|
require 'yard'
|
4
4
|
require 'redcarpet'
|
5
5
|
|
6
|
+
# rake test
|
6
7
|
Rake::TestTask.new do |t|
|
7
8
|
t.libs.push "lib"
|
8
9
|
t.test_files = FileList[File.expand_path('../test/**/*_test.rb', __FILE__)] -
|
@@ -10,6 +11,13 @@ Rake::TestTask.new do |t|
|
|
10
11
|
t.verbose = true
|
11
12
|
end
|
12
13
|
|
14
|
+
# rake test:integration
|
15
|
+
Rake::TestTask.new("test:integration") do |t|
|
16
|
+
t.libs.push "lib"
|
17
|
+
t.test_files = FileList[File.expand_path('../test/**/beaneater_test.rb', __FILE__)]
|
18
|
+
t.verbose = true
|
19
|
+
end
|
20
|
+
|
13
21
|
# rake test:full
|
14
22
|
Rake::TestTask.new("test:full") do |t|
|
15
23
|
t.libs.push "lib"
|
data/TODO
CHANGED
data/lib/beaneater/connection.rb
CHANGED
@@ -1,42 +1,50 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
3
|
module Beaneater
|
4
|
-
# Represents a connection to beanstalkd
|
4
|
+
# Represents a connection to a beanstalkd instance.
|
5
5
|
class Connection
|
6
6
|
|
7
|
-
# @!attribute telnet_connection
|
8
|
-
# @return [Net::Telnet] returns Telnet connection object
|
9
7
|
# @!attribute address
|
10
8
|
# @return [String] returns Beanstalkd server address
|
9
|
+
# @example
|
10
|
+
# @conn.address # => "localhost:11300"
|
11
11
|
# @!attribute host
|
12
12
|
# @return [String] returns Beanstalkd server host
|
13
|
+
# @example
|
14
|
+
# @conn.host # => "localhost"
|
13
15
|
# @!attribute port
|
14
16
|
# @return [Integer] returns Beanstalkd server port
|
15
|
-
|
17
|
+
# @example
|
18
|
+
# @conn.port # => "11300"
|
19
|
+
# @!attribute telnet_connection
|
20
|
+
# @return [Net::Telnet] returns Telnet connection object
|
21
|
+
attr_reader :address, :host, :port, :telnet_connection
|
16
22
|
|
17
|
-
# Default port value
|
23
|
+
# Default port value for beanstalk connection
|
18
24
|
DEFAULT_PORT = 11300
|
19
25
|
|
20
|
-
#
|
26
|
+
# Initializes new connection.
|
21
27
|
#
|
22
|
-
# @param [String] address beanstalkd address
|
28
|
+
# @param [String] address beanstalkd instance address.
|
23
29
|
# @example
|
24
30
|
# Beaneater::Connection.new('localhost')
|
25
31
|
# Beaneater::Connection.new('localhost:11300')
|
32
|
+
#
|
26
33
|
def initialize(address)
|
27
34
|
@address = address
|
28
35
|
@telnet_connection = establish_connection
|
29
36
|
@mutex = Mutex.new
|
30
37
|
end
|
31
38
|
|
32
|
-
# Send commands to beanstalkd server via telnet_connection
|
39
|
+
# Send commands to beanstalkd server via telnet_connection.
|
33
40
|
#
|
34
41
|
# @param [String] command Beanstalkd command
|
35
|
-
# @param [Hash] options Settings for telnet
|
42
|
+
# @param [Hash{Symbol => String,Boolean}] options Settings for telnet
|
36
43
|
# @option options [Boolean] FailEOF raises EOF Exeception
|
37
|
-
#
|
44
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response
|
38
45
|
# @example
|
39
|
-
# @
|
46
|
+
# @conn.transmit('bury 123')
|
47
|
+
#
|
40
48
|
def transmit(command, options={}, &block)
|
41
49
|
@mutex.lock
|
42
50
|
if telnet_connection
|
@@ -49,19 +57,21 @@ module Beaneater
|
|
49
57
|
@mutex.unlock
|
50
58
|
end
|
51
59
|
|
52
|
-
# Close connection with beanstalkd server
|
60
|
+
# Close connection with beanstalkd server.
|
53
61
|
#
|
54
62
|
# @example
|
55
|
-
# @
|
63
|
+
# @conn.close
|
64
|
+
#
|
56
65
|
def close
|
57
66
|
@telnet_connection.close
|
58
67
|
@telnet_connection = nil
|
59
68
|
end
|
60
69
|
|
61
|
-
# Returns string representation of job
|
70
|
+
# Returns string representation of job.
|
62
71
|
#
|
63
72
|
# @example
|
64
|
-
# @
|
73
|
+
# @conn.inspect
|
74
|
+
#
|
65
75
|
def to_s
|
66
76
|
"#<Beaneater::Connection host=#{host.inspect} port=#{port.inspect}>"
|
67
77
|
end
|
@@ -90,7 +100,7 @@ module Beaneater
|
|
90
100
|
#
|
91
101
|
# @param [String] cmd Beanstalk command transmitted
|
92
102
|
# @param [String] res Telnet command response
|
93
|
-
# @return [Hash] Beanstalk
|
103
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalk response with `status`, `id`, `body`, and `connection`
|
94
104
|
# @raise [Beaneater::UnexpectedResponse] Response from beanstalk command was an error status
|
95
105
|
# @example
|
96
106
|
# parse_response("delete 56", "DELETED 56\nFOO")
|
data/lib/beaneater/errors.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Beaneater
|
2
|
-
# Raises when
|
2
|
+
# Raises when a beanstalkd instance is no longer accessible.
|
3
3
|
class NotConnected < RuntimeError; end
|
4
4
|
# Raises when the tube name specified is invalid.
|
5
5
|
class InvalidTubeName < RuntimeError; end
|
@@ -15,13 +15,15 @@ module Beaneater
|
|
15
15
|
|
16
16
|
# @!attribute status
|
17
17
|
# @return [String] returns beanstalkd response status
|
18
|
+
# @example @ex.status # => "NOT_FOUND"
|
18
19
|
# @!attribute cmd
|
19
20
|
# @return [String] returns beanstalkd request command
|
21
|
+
# @example @ex.cmd # => "stats-job 23"
|
20
22
|
attr_reader :status, :cmd
|
21
23
|
|
22
24
|
# Initialize unexpected response error
|
23
25
|
#
|
24
|
-
# @param [UnexpectedResponse] status Unexpected response object
|
26
|
+
# @param [Beaneater::UnexpectedResponse] status Unexpected response object
|
25
27
|
# @param [String] cmd Beanstalkd request command
|
26
28
|
#
|
27
29
|
# @example
|
@@ -37,6 +39,7 @@ module Beaneater
|
|
37
39
|
# @param [String] status Beanstalkd error status
|
38
40
|
# @param [String] cmd Beanstalkd request command
|
39
41
|
#
|
42
|
+
# @return [Beaneater::UnexpectedResponse] Exception for the status provided
|
40
43
|
# @example
|
41
44
|
# Beaneater::UnexpectedResponse.new('NOT_FOUND', 'bury 123')
|
42
45
|
#
|
@@ -1,30 +1,29 @@
|
|
1
1
|
module Beaneater
|
2
|
-
# Exception to stop processing jobs
|
2
|
+
# Exception to stop processing jobs during a `process!` loop.
|
3
|
+
# Simply `raise AbortProcessingError` in any job process handler to stop the processing loop.
|
3
4
|
class AbortProcessingError < RuntimeError; end
|
4
5
|
|
5
|
-
# Represents collection of
|
6
|
+
# Represents collection of job-related commands.
|
6
7
|
class Jobs < PoolCommand
|
7
8
|
|
8
9
|
# @!attribute processors
|
9
10
|
# @return [Array<Proc>] returns Collection of proc to handle beanstalkd jobs
|
10
11
|
attr_reader :processors
|
11
12
|
|
12
|
-
# Number of retries to process a job
|
13
|
+
# Number of retries to process a job.
|
13
14
|
MAX_RETRIES = 3
|
14
15
|
|
15
|
-
# Delay in seconds before to make job ready again
|
16
|
+
# Delay in seconds before to make job ready again.
|
16
17
|
RELEASE_DELAY = 1
|
17
18
|
|
18
|
-
# Peek (or find)
|
19
|
-
#
|
20
|
-
# @param [Integer] id Job id
|
21
|
-
#
|
22
|
-
# @raise [Beaneater::NotFoundError] Job not found
|
19
|
+
# Peek (or find) first job from beanstalkd pool.
|
23
20
|
#
|
21
|
+
# @param [Integer] id Job id to find
|
22
|
+
# @return [Beaneater::Job] Job matching given id
|
24
23
|
# @example
|
24
|
+
# @beaneater_pool.jobs[123] # => <Beaneater::Job>
|
25
25
|
# @beaneater_pool.jobs.find(123) # => <Beaneater::Job>
|
26
26
|
# @beaneater_pool.jobs.peek(123) # => <Beaneater::Job>
|
27
|
-
# @beaneater_pool.jobs.find[123] # => <Beaneater::Job>
|
28
27
|
#
|
29
28
|
# @api public
|
30
29
|
def find(id)
|
@@ -36,13 +35,28 @@ module Beaneater
|
|
36
35
|
alias_method :peek, :find
|
37
36
|
alias_method :[], :find
|
38
37
|
|
39
|
-
#
|
38
|
+
# Find all jobs with specified id fromm all beanstalkd servers in pool.
|
39
|
+
#
|
40
|
+
# @param [Integer] id Job id to find
|
41
|
+
# @return [Array<Beaneater::Job>] Jobs matching given id
|
42
|
+
# @example
|
43
|
+
# @beaneater_pool.jobs.find_all(123) # => [<Beaneater::Job>, <Beaneater::Job>]
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def find_all(id)
|
47
|
+
res = transmit_to_all("peek #{id}")
|
48
|
+
res.compact.map { |r| Job.new(r) }
|
49
|
+
rescue Beaneater::NotFoundError => ex
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Register a processor to handle beanstalkd job on particular tube.
|
40
54
|
#
|
41
55
|
# @param [String] tube_name Tube name
|
42
|
-
# @param [Hash] options settings for processor
|
56
|
+
# @param [Hash{String=>RuntimeError}] options settings for processor
|
57
|
+
# @param [Proc] block Process beanstalkd job
|
43
58
|
# @option options [Integer] max_retries Number of retries to process a job
|
44
59
|
# @option options [Array<RuntimeError>] retry_on Collection of errors to rescue and re-run processor
|
45
|
-
# @param [Proc] block Process beanstalkd job
|
46
60
|
#
|
47
61
|
# @example
|
48
62
|
# @beanstalk.jobs.register('some-tube', :retry_on => [SomeError]) do |job|
|
@@ -61,10 +75,10 @@ module Beaneater
|
|
61
75
|
@processors[tube_name.to_s] = { :block => block, :retry_on => retry_on, :max_retries => max_retries }
|
62
76
|
end
|
63
77
|
|
64
|
-
# Watch, reserve, process and delete or bury or release jobs
|
78
|
+
# Watch, reserve, process and delete or bury or release jobs.
|
65
79
|
#
|
66
|
-
# @param [Hash] options Settings for processing
|
67
|
-
# @option options [Integer] Delay in seconds before to make job ready again
|
80
|
+
# @param [Hash{String => Integer}] options Settings for processing
|
81
|
+
# @option options [Integer] release_delay Delay in seconds before to make job ready again
|
68
82
|
#
|
69
83
|
# @api public
|
70
84
|
def process!(options={})
|
data/lib/beaneater/job/record.rb
CHANGED
@@ -3,19 +3,20 @@ module Beaneater
|
|
3
3
|
class Job
|
4
4
|
|
5
5
|
# @!attribute id
|
6
|
-
# @return [Integer]
|
6
|
+
# @return [Integer] id for the job.
|
7
7
|
# @!attribute body
|
8
|
-
# @return [String]
|
8
|
+
# @return [String] the job's body.
|
9
9
|
# @!attribute connection
|
10
|
-
# @return [Beaneater::Connection]
|
10
|
+
# @return [Beaneater::Connection] connection which has retrieved job.
|
11
11
|
# @!attribute reserved
|
12
|
-
# @return [Boolean]
|
12
|
+
# @return [Boolean] whether the job has been reserved.
|
13
13
|
attr_reader :id, :body, :connection, :reserved
|
14
14
|
|
15
15
|
|
16
|
-
#
|
16
|
+
# Initializes a new job object.
|
17
|
+
#
|
18
|
+
# @param [Hash{Symbol => String,Number}] res Result from beanstalkd response
|
17
19
|
#
|
18
|
-
# @param [Hash] res result from beanstalkd response
|
19
20
|
def initialize(res)
|
20
21
|
@id = res[:id]
|
21
22
|
@body = res[:body]
|
@@ -23,9 +24,9 @@ module Beaneater
|
|
23
24
|
@reserved = res[:status] == 'RESERVED'
|
24
25
|
end
|
25
26
|
|
26
|
-
#
|
27
|
+
# Sends command to bury a reserved job.
|
27
28
|
#
|
28
|
-
# @param [Hash] options Settings to bury job
|
29
|
+
# @param [Hash{Symbol => Integer}] options Settings to bury job
|
29
30
|
# @option options [Integer] pri Assign new priority to job
|
30
31
|
#
|
31
32
|
# @example
|
@@ -39,12 +40,11 @@ module Beaneater
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
#
|
43
|
+
# Sends command to release a job back to ready state.
|
43
44
|
#
|
44
|
-
# @param [Hash] options Settings to release job
|
45
|
+
# @param [Hash{String => Integer}] options Settings to release job
|
45
46
|
# @option options [Integer] pri Assign new priority to job
|
46
|
-
# @option options [Integer]
|
47
|
-
#
|
47
|
+
# @option options [Integer] delay Assign new delay to job
|
48
48
|
# @example
|
49
49
|
# @beaneater_connection.jobs.find(123).release(:pri => 10, :delay => 5)
|
50
50
|
#
|
@@ -56,7 +56,7 @@ module Beaneater
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
#
|
59
|
+
# Sends command to touch job which extends the ttr.
|
60
60
|
#
|
61
61
|
# @example
|
62
62
|
# @beaneater_connection.jobs.find(123).touch
|
@@ -66,7 +66,7 @@ module Beaneater
|
|
66
66
|
with_reserved("touch #{id}")
|
67
67
|
end
|
68
68
|
|
69
|
-
#
|
69
|
+
# Sends command to delete a job.
|
70
70
|
#
|
71
71
|
# @example
|
72
72
|
# @beaneater_connection.jobs.find(123).delete
|
@@ -76,7 +76,7 @@ module Beaneater
|
|
76
76
|
transmit("delete #{id}") { @reserved = false }
|
77
77
|
end
|
78
78
|
|
79
|
-
#
|
79
|
+
# Sends command to kick a buried job.
|
80
80
|
#
|
81
81
|
# @example
|
82
82
|
# @beaneater_connection.jobs.find(123).kick
|
@@ -86,10 +86,12 @@ module Beaneater
|
|
86
86
|
transmit("kick-job #{id}")
|
87
87
|
end
|
88
88
|
|
89
|
-
#
|
89
|
+
# Sends command to get stats about job.
|
90
90
|
#
|
91
|
+
# @return [Beaneater::StatStruct] struct filled with relevant job stats
|
91
92
|
# @example
|
92
93
|
# @beaneater_connection.jobs.find(123).stats
|
94
|
+
# @job.stats.tube # => "some-tube"
|
93
95
|
#
|
94
96
|
# @api public
|
95
97
|
def stats
|
@@ -97,8 +99,9 @@ module Beaneater
|
|
97
99
|
StatStruct.from_hash(res[:body])
|
98
100
|
end
|
99
101
|
|
100
|
-
# Check if job is
|
102
|
+
# Check if job is currently in a reserved state.
|
101
103
|
#
|
104
|
+
# @return [Boolean] Returns true if the job is in a reserved state
|
102
105
|
# @example
|
103
106
|
# @beaneater_connection.jobs.find(123).reserved?
|
104
107
|
#
|
@@ -107,35 +110,70 @@ module Beaneater
|
|
107
110
|
@reserved || self.stats.state == "reserved"
|
108
111
|
end
|
109
112
|
|
110
|
-
# Check if job exists
|
113
|
+
# Check if the job still exists.
|
111
114
|
#
|
115
|
+
# @return [Boolean] Returns true if the job still exists
|
112
116
|
# @example
|
113
117
|
# @beaneater_connection.jobs.find(123).exists?
|
114
118
|
#
|
115
119
|
# @api public
|
116
120
|
def exists?
|
117
|
-
|
121
|
+
!self.stats.nil?
|
118
122
|
rescue Beaneater::NotFoundError
|
119
123
|
false
|
120
124
|
end
|
121
125
|
|
122
126
|
# Returns the name of the tube this job is in
|
123
127
|
#
|
128
|
+
# @return [String] The name of the tube for this job
|
124
129
|
# @example
|
125
130
|
# @beaneater_connection.jobs.find(123).tube
|
131
|
+
# # => "some-tube"
|
126
132
|
#
|
127
|
-
# @api public
|
128
133
|
def tube
|
129
134
|
self.stats && self.stats.tube
|
130
135
|
end
|
131
136
|
|
137
|
+
# Returns the ttr of this job
|
138
|
+
#
|
139
|
+
# @return [String] The ttr of this job
|
140
|
+
# @example
|
141
|
+
# @beaneater_connection.jobs.find(123).ttr
|
142
|
+
# # => 123
|
143
|
+
#
|
144
|
+
def ttr
|
145
|
+
self.stats && self.stats.ttr
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the pri of this job
|
149
|
+
#
|
150
|
+
# @return [String] The pri of this job
|
151
|
+
# @example
|
152
|
+
# @beaneater_connection.jobs.find(123).pri
|
153
|
+
# # => 1
|
154
|
+
#
|
155
|
+
def pri
|
156
|
+
self.stats && self.stats.pri
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns the delay of this job
|
160
|
+
#
|
161
|
+
# @return [String] The delay of this job
|
162
|
+
# @example
|
163
|
+
# @beaneater_connection.jobs.find(123).delay
|
164
|
+
# # => 5
|
165
|
+
#
|
166
|
+
def delay
|
167
|
+
self.stats && self.stats.delay
|
168
|
+
end
|
169
|
+
|
132
170
|
# Returns string representation of job
|
133
171
|
#
|
172
|
+
# @return [String] string representation
|
134
173
|
# @example
|
135
174
|
# @beaneater_connection.jobs.find(123).to_s
|
136
175
|
# @beaneater_connection.jobs.find(123).inspect
|
137
176
|
#
|
138
|
-
# @api public
|
139
177
|
def to_s
|
140
178
|
"#<Beaneater::Job id=#{id} body=#{body.inspect}>"
|
141
179
|
end
|
@@ -146,7 +184,7 @@ module Beaneater
|
|
146
184
|
# Transmit command to beanstalkd instances and fetch response.
|
147
185
|
#
|
148
186
|
# @param [String] cmd Beanstalkd command to send.
|
149
|
-
# @return [Hash] Beanstalkd response for the command.
|
187
|
+
# @return [Hash{Symbol => String,Number}] Beanstalkd response for the command.
|
150
188
|
# @example
|
151
189
|
# transmit('stats')
|
152
190
|
# transmit('stats') { 'success' }
|
@@ -160,7 +198,7 @@ module Beaneater
|
|
160
198
|
# Transmits a command which requires the job to be reserved.
|
161
199
|
#
|
162
200
|
# @param [String] cmd Beanstalkd command to send.
|
163
|
-
# @return [Hash] Beanstalkd response for the command.
|
201
|
+
# @return [Hash{Symbol => String,Number}] Beanstalkd response for the command.
|
164
202
|
# @raise [Beaneater::JobNotReserved] Command cannot execute since job is not reserved.
|
165
203
|
# @example
|
166
204
|
# with_reserved("bury 26") { @reserved = false }
|
data/lib/beaneater/pool.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Simple ruby client for beanstalkd.
|
1
|
+
# Simple ruby client for interacting with beanstalkd.
|
2
2
|
module Beaneater
|
3
|
-
# Represents collection of connections.
|
3
|
+
# Represents collection of beanstalkd connections.
|
4
4
|
class Pool
|
5
5
|
# Default number of retries to send a command to a connection
|
6
6
|
MAX_RETRIES = 3
|
@@ -11,8 +11,7 @@ module Beaneater
|
|
11
11
|
|
12
12
|
# Initialize new connection
|
13
13
|
#
|
14
|
-
# @param [Array]
|
15
|
-
#
|
14
|
+
# @param [Array<String>] addresses Array of beanstalkd server addresses
|
16
15
|
# @example
|
17
16
|
# Beaneater::Pool.new(['localhost:11300', '127.0.0.1:11300'])
|
18
17
|
#
|
@@ -20,54 +19,92 @@ module Beaneater
|
|
20
19
|
# @bp = Beaneater::Pool.new
|
21
20
|
# @bp.connections.first.host # => 'localhost'
|
22
21
|
# @bp.connections.last.host # => '127.0.0.1'
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
#
|
23
|
+
def initialize(addresses=nil)
|
24
|
+
addresses = addresses || host_from_env
|
25
|
+
@connections = Array(addresses).map { |a| Connection.new(a) }
|
26
26
|
end
|
27
27
|
|
28
|
-
# Returns Beaneater::Stats object
|
28
|
+
# Returns Beaneater::Stats object for accessing beanstalk stats.
|
29
29
|
#
|
30
|
+
# @return [Beaneater::Stats] stats object
|
30
31
|
# @api public
|
31
32
|
def stats
|
32
33
|
@stats ||= Stats.new(self)
|
33
34
|
end
|
34
35
|
|
35
|
-
# Returns Beaneater::Jobs object
|
36
|
+
# Returns Beaneater::Jobs object for accessing job related functions.
|
36
37
|
#
|
38
|
+
# @return [Beaneater::Jobs] jobs object
|
37
39
|
# @api public
|
38
40
|
def jobs
|
39
41
|
@jobs ||= Jobs.new(self)
|
40
42
|
end
|
41
43
|
|
42
|
-
# Returns Beaneater::Tubes object
|
44
|
+
# Returns Beaneater::Tubes object for accessing tube related functions.
|
43
45
|
#
|
46
|
+
# @return [Beaneater::Tubes] tubes object
|
44
47
|
# @api public
|
45
48
|
def tubes
|
46
49
|
@tubes ||= Tubes.new(self)
|
47
50
|
end
|
48
51
|
|
49
|
-
#
|
52
|
+
# Sends command to every beanstalkd server set in the pool.
|
50
53
|
#
|
51
54
|
# @param [String] command Beanstalkd command
|
52
|
-
# @param [Hash] options telnet connections options
|
53
|
-
# @param [Proc] block Block passed
|
54
|
-
#
|
55
|
+
# @param [Hash{String => String, Boolean}] options telnet connections options
|
56
|
+
# @param [Proc] block Block passed to telnet connection during transmit
|
57
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response from each instance
|
55
58
|
# @example
|
56
59
|
# @pool.transmit_to_all("stats")
|
60
|
+
#
|
57
61
|
def transmit_to_all(command, options={}, &block)
|
58
|
-
|
59
|
-
|
60
|
-
|
62
|
+
res_exception = nil
|
63
|
+
res = connections.map { |conn|
|
64
|
+
begin
|
65
|
+
safe_transmit { conn.transmit(command, options, &block) }
|
66
|
+
rescue UnexpectedResponse => ex # not the correct status
|
67
|
+
res_exception = ex
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
}.compact
|
71
|
+
raise res_exception if res.none? && res_exception
|
72
|
+
res
|
61
73
|
end
|
62
74
|
|
63
|
-
# Send command to
|
75
|
+
# Send command to each beanstalkd servers until getting response expected
|
64
76
|
#
|
65
77
|
# @param [String] command Beanstalkd command
|
66
|
-
# @param [Hash] options telnet connections options
|
78
|
+
# @param [Hash{String => String, Boolean}] options telnet connections options
|
67
79
|
# @param [Proc] block Block passed in telnet connection object
|
80
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response from the instance
|
81
|
+
# @example
|
82
|
+
# @pool.transmit_until_res('peek-ready', :status => "FOUND", &block)
|
83
|
+
#
|
84
|
+
def transmit_until_res(command, options={}, &block)
|
85
|
+
status_expected = options.delete(:status)
|
86
|
+
res_exception = nil
|
87
|
+
connections.each do |conn|
|
88
|
+
begin
|
89
|
+
res = safe_transmit { conn.transmit(command, options, &block) }
|
90
|
+
return res if res[:status] == status_expected
|
91
|
+
rescue UnexpectedResponse => ex # not the correct status
|
92
|
+
res_exception = ex
|
93
|
+
next
|
94
|
+
end
|
95
|
+
end
|
96
|
+
raise res_exception if res_exception
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sends command to a random beanstalkd server in the pool.
|
68
100
|
#
|
101
|
+
# @param [String] command Beanstalkd command
|
102
|
+
# @param [Hash{String => String,Boolean}] options telnet connections options
|
103
|
+
# @param [Proc] block Block passed in telnet connection object
|
104
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response from the instance
|
69
105
|
# @example
|
70
106
|
# @pool.transmit_to_rand("stats", :match => /\n/)
|
107
|
+
#
|
71
108
|
def transmit_to_rand(command, options={}, &block)
|
72
109
|
safe_transmit do
|
73
110
|
conn = connections.respond_to?(:sample) ? connections.sample : connections.choice
|
@@ -75,23 +112,11 @@ module Beaneater
|
|
75
112
|
end
|
76
113
|
end
|
77
114
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# @param [String] command Beanstalkd command
|
81
|
-
# @param [Hash] options telnet connections options
|
82
|
-
# @param [Proc] block Block passed in telnet connection object
|
115
|
+
# Closes all connections within the pool.
|
83
116
|
#
|
84
117
|
# @example
|
85
|
-
#
|
86
|
-
|
87
|
-
status_expected = options.delete(:status)
|
88
|
-
connections.each do |conn|
|
89
|
-
res = safe_transmit { conn.transmit(command, options, &block) }
|
90
|
-
return res if res[:status] == status_expected
|
91
|
-
end && nil
|
92
|
-
end
|
93
|
-
|
94
|
-
# Closes all connections within pool
|
118
|
+
# @pool.close
|
119
|
+
#
|
95
120
|
def close
|
96
121
|
while @connections.any?
|
97
122
|
conn = @connections.pop
|
@@ -14,20 +14,21 @@ module Beaneater
|
|
14
14
|
@pool = pool
|
15
15
|
end
|
16
16
|
|
17
|
-
# Delegate to Pool#transmit_to_all and if needed will merge responses from beanstalkd
|
17
|
+
# Delegate to Pool#transmit_to_all and if needed will merge responses from beanstalkd.
|
18
18
|
#
|
19
19
|
# @param [String] body Beanstalkd command
|
20
|
-
# @param [Hash] options telnet connections options
|
20
|
+
# @param [Hash{String => String, Boolean}] options telnet connections options
|
21
21
|
# @option options [Boolean] merge Ask for merging responses or not
|
22
22
|
# @param [Proc] block Block passed in telnet connection object
|
23
|
-
#
|
24
23
|
# @example
|
25
24
|
# @pool.transmit_to_all("stats")
|
25
|
+
#
|
26
26
|
def transmit_to_all(body, options={}, &block)
|
27
27
|
merge = options.delete(:merge)
|
28
28
|
res = pool.transmit_to_all(body, options, &block)
|
29
|
-
|
30
|
-
|
29
|
+
first = res.find { |r| r && r[:status] }
|
30
|
+
if first && merge
|
31
|
+
res = { :status => first[:status], :body => sum_items(res.map { |r| r[:body] }) }
|
31
32
|
end
|
32
33
|
res
|
33
34
|
end
|
@@ -44,17 +45,24 @@ module Beaneater
|
|
44
45
|
|
45
46
|
protected
|
46
47
|
|
47
|
-
# Selects
|
48
|
+
# Selects items from collection and then merges the individual values
|
49
|
+
# Supports array of hashes or array of arrays
|
48
50
|
#
|
49
|
-
# @param [Array<Hash>] hs Collection of
|
50
|
-
# @return [Hash] Merged responses combining values from all the hash bodies
|
51
|
+
# @param [Array<Hash, Array>] hs Collection of responses returned from beanstalkd
|
52
|
+
# @return [Hash{Symbol => String}] Merged responses combining values from all the hash bodies
|
51
53
|
# @example
|
52
|
-
# self.
|
54
|
+
# self.sum_items([{ :foo => 1, :bar => 5 }, { :foo => 2, :bar => 3 }])
|
53
55
|
# => { :foo => 3, :bar => 8 }
|
56
|
+
# self.sum_items([['foo', 'bar'], ['foo', 'bar', 'baz']])
|
57
|
+
# => ['foo', 'bar', 'baz']
|
54
58
|
#
|
55
|
-
def
|
56
|
-
|
57
|
-
|
59
|
+
def sum_items(items)
|
60
|
+
if items.first.is_a?(Hash)
|
61
|
+
items.select { |h| h.is_a?(Hash) }.
|
62
|
+
inject({}) { |a,b| a.merge(b) { |k,o,n| combine_stats(k, o, n) } }
|
63
|
+
elsif items.first.is_a?(Array)
|
64
|
+
items.flatten.uniq
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
# Combine two values for given key
|
@@ -3,7 +3,7 @@ module Beaneater
|
|
3
3
|
class StatStruct < FasterOpenStruct
|
4
4
|
# Convert a stats hash into a struct.
|
5
5
|
#
|
6
|
-
# @param [Hash
|
6
|
+
# @param [Hash{String => String}] hash Hash Stats hash to convert to struct
|
7
7
|
# @return [Beaneater::StatStruct, nil] Stats struct from hash
|
8
8
|
# @example
|
9
9
|
# s = StatStruct.from_hash(:foo => "bar")
|
@@ -18,7 +18,7 @@ module Beaneater
|
|
18
18
|
# Access value for stat with specified key.
|
19
19
|
#
|
20
20
|
# @param [String] key Key to fetch from stats.
|
21
|
-
# @return [String,Integer] Value for specified stat key.
|
21
|
+
# @return [String, Integer] Value for specified stat key.
|
22
22
|
# @example
|
23
23
|
# @stats['foo'] # => "bar"
|
24
24
|
#
|
data/lib/beaneater/stats.rb
CHANGED
@@ -22,6 +22,7 @@ module Beaneater
|
|
22
22
|
# @pool.tubes['tube2']
|
23
23
|
# # => <Beaneater::Tube name="tube2">
|
24
24
|
#
|
25
|
+
# @api public
|
25
26
|
def find(tube_name)
|
26
27
|
Tube.new(self.pool, tube_name)
|
27
28
|
end
|
@@ -37,6 +38,7 @@ module Beaneater
|
|
37
38
|
# @conn.tubes.reserve { |job| process(job) }
|
38
39
|
# # => <Beaneater::Job id=5 body="foo">
|
39
40
|
#
|
41
|
+
# @api public
|
40
42
|
def reserve(timeout=nil, &block)
|
41
43
|
res = transmit_to_rand(timeout ? "reserve-with-timeout #{timeout}" : 'reserve')
|
42
44
|
job = Job.new(res)
|
@@ -44,20 +46,6 @@ module Beaneater
|
|
44
46
|
job
|
45
47
|
end
|
46
48
|
|
47
|
-
# Set specified tube as used.
|
48
|
-
#
|
49
|
-
# @param [String] tube Tube to be used.
|
50
|
-
# @example
|
51
|
-
# @conn.tubes.use("some-tube")
|
52
|
-
#
|
53
|
-
def use(tube)
|
54
|
-
return tube if @last_used == tube
|
55
|
-
res = transmit_to_all("use #{tube}")
|
56
|
-
@last_used = tube
|
57
|
-
rescue BadFormatError
|
58
|
-
raise InvalidTubeName, "Tube cannot be named '#{tube}'"
|
59
|
-
end
|
60
|
-
|
61
49
|
# List of all known beanstalk tubes.
|
62
50
|
#
|
63
51
|
# @return [Array<Beaneater::Tube>] List of all beanstalk tubes.
|
@@ -65,8 +53,9 @@ module Beaneater
|
|
65
53
|
# @pool.tubes.all
|
66
54
|
# # => [<Beaneater::Tube name="tube2">, <Beaneater::Tube name="tube3">]
|
67
55
|
#
|
56
|
+
# @api public
|
68
57
|
def all
|
69
|
-
|
58
|
+
transmit_to_all('list-tubes', :merge => true)[:body].map { |tube_name| Tube.new(self.pool, tube_name) }
|
70
59
|
end
|
71
60
|
|
72
61
|
# List of watched beanstalk tubes.
|
@@ -76,8 +65,9 @@ module Beaneater
|
|
76
65
|
# @pool.tubes.watched
|
77
66
|
# # => [<Beaneater::Tube name="tube2">, <Beaneater::Tube name="tube3">]
|
78
67
|
#
|
68
|
+
# @api public
|
79
69
|
def watched
|
80
|
-
|
70
|
+
transmit_to_all('list-tubes-watched', :merge => true)[:body].map { |tube_name| Tube.new(self.pool, tube_name) }
|
81
71
|
end
|
82
72
|
|
83
73
|
# Currently used beanstalk tube.
|
@@ -87,6 +77,7 @@ module Beaneater
|
|
87
77
|
# @pool.tubes.used
|
88
78
|
# # => <Beaneater::Tube name="tube2">
|
89
79
|
#
|
80
|
+
# @api public
|
90
81
|
def used
|
91
82
|
Tube.new(self.pool, transmit_to_rand('list-tube-used')[:id])
|
92
83
|
end
|
@@ -98,6 +89,7 @@ module Beaneater
|
|
98
89
|
# @example
|
99
90
|
# @pool.tubes.watch('foo', 'bar')
|
100
91
|
#
|
92
|
+
# @api public
|
101
93
|
def watch(*names)
|
102
94
|
names.each do |t|
|
103
95
|
transmit_to_all "watch #{t}"
|
@@ -113,6 +105,7 @@ module Beaneater
|
|
113
105
|
# @example
|
114
106
|
# @pool.tubes.watch!('foo', 'bar')
|
115
107
|
#
|
108
|
+
# @api public
|
116
109
|
def watch!(*names)
|
117
110
|
old_tubes = watched.map(&:name) - names.map(&:to_s)
|
118
111
|
watch(*names)
|
@@ -125,10 +118,25 @@ module Beaneater
|
|
125
118
|
# @example
|
126
119
|
# @pool.tubes.ignore('foo', 'bar')
|
127
120
|
#
|
121
|
+
# @api public
|
128
122
|
def ignore(*names)
|
129
123
|
names.each do |w|
|
130
124
|
transmit_to_all "ignore #{w}"
|
131
125
|
end
|
132
126
|
end
|
127
|
+
|
128
|
+
# Set specified tube as used.
|
129
|
+
#
|
130
|
+
# @param [String] tube Tube to be used.
|
131
|
+
# @example
|
132
|
+
# @conn.tubes.use("some-tube")
|
133
|
+
#
|
134
|
+
def use(tube)
|
135
|
+
return tube if @last_used == tube
|
136
|
+
res = transmit_to_all("use #{tube}")
|
137
|
+
@last_used = tube
|
138
|
+
rescue BadFormatError
|
139
|
+
raise InvalidTubeName, "Tube cannot be named '#{tube}'"
|
140
|
+
end
|
133
141
|
end # Tubes
|
134
142
|
end # Beaneater
|
@@ -28,11 +28,11 @@ module Beaneater
|
|
28
28
|
# Inserts job with specified body onto tube.
|
29
29
|
#
|
30
30
|
# @param [String] body The data to store with this job.
|
31
|
-
# @param [Hash] options The settings associated with this job.
|
31
|
+
# @param [Hash{String => Integer}] options The settings associated with this job.
|
32
32
|
# @option options [Integer] pri priority for this job
|
33
33
|
# @option options [Integer] ttr time to respond for this job
|
34
34
|
# @option options [Integer] delay delay for this job
|
35
|
-
# @return [Hash] beanstalkd command response
|
35
|
+
# @return [Hash{String => String, Number}] beanstalkd command response
|
36
36
|
# @example
|
37
37
|
# @tube.put "data", :pri => 1000, :ttr => 10, :delay => 5
|
38
38
|
#
|
@@ -71,6 +71,7 @@ module Beaneater
|
|
71
71
|
# @example
|
72
72
|
# @tube.reserve # => <Beaneater::Job id=5 body=foo>
|
73
73
|
#
|
74
|
+
# @api public
|
74
75
|
def reserve(timeout=nil, &block)
|
75
76
|
pool.tubes.watch!(self.name)
|
76
77
|
pool.tubes.reserve(timeout, &block)
|
@@ -79,10 +80,11 @@ module Beaneater
|
|
79
80
|
# Kick specified number of jobs from buried to ready state.
|
80
81
|
#
|
81
82
|
# @param [Integer] bounds The number of jobs to kick.
|
82
|
-
# @return [Hash] Beanstalkd command response
|
83
|
+
# @return [Hash{String => String, Number}] Beanstalkd command response
|
83
84
|
# @example
|
84
85
|
# @tube.kick(5)
|
85
86
|
#
|
87
|
+
# @api public
|
86
88
|
def kick(bounds=1)
|
87
89
|
safe_use { transmit_to_rand("kick #{bounds}") }
|
88
90
|
end
|
@@ -93,6 +95,7 @@ module Beaneater
|
|
93
95
|
# @example
|
94
96
|
# @tube.stats.delayed # => 24
|
95
97
|
#
|
98
|
+
# @api public
|
96
99
|
def stats
|
97
100
|
res = transmit_to_all("stats-tube #{name}", :merge => true)
|
98
101
|
StatStruct.from_hash(res[:body])
|
@@ -101,10 +104,11 @@ module Beaneater
|
|
101
104
|
# Pause the execution of this tube for specified `delay`.
|
102
105
|
#
|
103
106
|
# @param [Integer] delay Number of seconds to delay tube execution
|
104
|
-
# @return [Hash] Beanstalkd command response
|
107
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response
|
105
108
|
# @example
|
106
109
|
# @tube.pause(10)
|
107
110
|
#
|
111
|
+
# @api public
|
108
112
|
def pause(delay)
|
109
113
|
transmit_to_all("pause-tube #{name} #{delay}")
|
110
114
|
end
|
data/lib/beaneater/version.rb
CHANGED
data/lib/beaneater.rb
CHANGED
data/test/beaneater_test.rb
CHANGED
@@ -3,6 +3,7 @@ require File.expand_path('../test_helper', __FILE__)
|
|
3
3
|
describe "beanstalk-client" do
|
4
4
|
before do
|
5
5
|
@beanstalk = Beaneater::Pool.new(['127.0.0.1:11300'])
|
6
|
+
# @beanstalk = Beaneater::Pool.new(['127.0.0.1:11300', '127.0.0.1:11301'])
|
6
7
|
@tubes = ['one', 'two', 'three']
|
7
8
|
|
8
9
|
# Put something on each tube so they exist
|
data/test/job_test.rb
CHANGED
@@ -207,6 +207,44 @@ describe Beaneater::Job do
|
|
207
207
|
end
|
208
208
|
end # tube
|
209
209
|
|
210
|
+
describe "for #pri" do
|
211
|
+
before do
|
212
|
+
@tube.put 'bar', :pri => 1
|
213
|
+
@job = @tube.peek(:ready)
|
214
|
+
end
|
215
|
+
|
216
|
+
it("should return pri") do
|
217
|
+
job = @tube.reserve
|
218
|
+
assert_equal 1, job.pri
|
219
|
+
job.release
|
220
|
+
end
|
221
|
+
end # tube
|
222
|
+
|
223
|
+
|
224
|
+
describe "for #ttr" do
|
225
|
+
before do
|
226
|
+
@tube.put 'bar', :ttr => 5
|
227
|
+
@job = @tube.peek(:ready)
|
228
|
+
end
|
229
|
+
|
230
|
+
it("should return ttr") do
|
231
|
+
job = @tube.reserve
|
232
|
+
assert_equal 5, job.ttr
|
233
|
+
job.release
|
234
|
+
end
|
235
|
+
end # tube
|
236
|
+
|
237
|
+
describe "for #delay" do
|
238
|
+
before do
|
239
|
+
@tube.put 'bar', :delay => 5
|
240
|
+
@job = @tube.peek(:delayed)
|
241
|
+
end
|
242
|
+
|
243
|
+
it("should return delay") do
|
244
|
+
assert_equal 5, @job.delay
|
245
|
+
end
|
246
|
+
end # tube
|
247
|
+
|
210
248
|
after do
|
211
249
|
cleanup_tubes!(['tube'])
|
212
250
|
end
|
data/test/jobs_test.rb
CHANGED
@@ -33,6 +33,30 @@ describe Beaneater::Jobs do
|
|
33
33
|
end
|
34
34
|
end # find
|
35
35
|
|
36
|
+
describe "for #find_all" do
|
37
|
+
before do
|
38
|
+
@time = Time.now.to_i
|
39
|
+
@tube.put("foo find #{@time}")
|
40
|
+
@job = @tube.peek(:ready)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return job from id" do
|
44
|
+
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return job using peek" do
|
48
|
+
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return job using hash syntax" do
|
52
|
+
assert_equal "foo find #{@time}", @jobs.find_all(@job.id).first.body
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return nil for invalid id" do
|
56
|
+
assert_equal [], @jobs.find_all(-1)
|
57
|
+
end
|
58
|
+
end # find_all
|
59
|
+
|
36
60
|
describe "for #register!" do
|
37
61
|
before do
|
38
62
|
$foo = 0
|
data/test/pool_command_test.rb
CHANGED
@@ -18,27 +18,49 @@ describe Beaneater::PoolCommand do
|
|
18
18
|
describe 'for #transmit_to_all' do
|
19
19
|
describe 'for regular command' do
|
20
20
|
before do
|
21
|
-
@pool = stub(:transmit_to_all => "OK")
|
21
|
+
@pool = stub(:transmit_to_all => [{ :body => "foo", :status => "OK" }])
|
22
22
|
@command = Beaneater::PoolCommand.new(@pool)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "can run regular command" do
|
26
|
-
|
26
|
+
res = @command.transmit_to_all("foo")
|
27
|
+
assert_equal "OK", res[0][:status]
|
28
|
+
assert_equal "foo", res[0][:body]
|
27
29
|
end
|
28
30
|
end # regular command
|
29
31
|
|
30
|
-
describe 'for
|
32
|
+
describe 'for merge command with hashes' do
|
31
33
|
before do
|
32
|
-
@pool = stub(:transmit_to_all => [
|
34
|
+
@pool = stub(:transmit_to_all => [
|
35
|
+
{ :body => { 'x' => 1, 'version' => 1.1 }, :status => "OK"},
|
36
|
+
{ :body => { 'x' => 3,'version' => 1.2 }, :status => "OK" }
|
37
|
+
])
|
33
38
|
@command = Beaneater::PoolCommand.new(@pool)
|
34
39
|
end
|
35
40
|
|
36
|
-
it "can run merge command" do
|
41
|
+
it "can run merge command " do
|
37
42
|
cmd = @command.transmit_to_all("bar", :merge => true)
|
43
|
+
assert_equal "OK", cmd[:status]
|
38
44
|
assert_equal 4, cmd[:body]['x']
|
39
45
|
assert_equal Set[1.1, 1.2], cmd[:body]['version']
|
40
46
|
end
|
41
47
|
end # merged command
|
48
|
+
|
49
|
+
describe 'for merge command with arrays' do
|
50
|
+
before do
|
51
|
+
@pool = stub(:transmit_to_all => [
|
52
|
+
{ :body => ['foo', 'bar'], :status => "OK"},
|
53
|
+
{ :body => ['foo', 'bar', 'baz'], :status => "OK" }
|
54
|
+
])
|
55
|
+
@command = Beaneater::PoolCommand.new(@pool)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can run merge command " do
|
59
|
+
cmd = @command.transmit_to_all("bar", :merge => true)
|
60
|
+
assert_equal "OK", cmd[:status]
|
61
|
+
assert_equal ['foo', 'bar', 'baz'].sort, cmd[:body].sort
|
62
|
+
end
|
63
|
+
end # merged command
|
42
64
|
end # transmit_to_all
|
43
65
|
|
44
66
|
describe 'for #method_missing' do
|
data/test/stats_test.rb
CHANGED
@@ -4,7 +4,8 @@ require File.expand_path('../test_helper', __FILE__)
|
|
4
4
|
|
5
5
|
describe Beaneater::Stats do
|
6
6
|
before do
|
7
|
-
@pool = stub(:transmit_to_all => [{ :body => { 'uptime' => 1, 'cmd-use' => 2 }
|
7
|
+
@pool = stub(:transmit_to_all => [{ :body => { 'uptime' => 1, 'cmd-use' => 2 }, :status => "OK"},
|
8
|
+
{:body => { 'uptime' => 3,'cmd-use' => 4 }, :status => "OK" }])
|
8
9
|
@stats = Beaneater::Stats.new(@pool)
|
9
10
|
end
|
10
11
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beaneater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -100,10 +100,10 @@ extra_rdoc_files: []
|
|
100
100
|
files:
|
101
101
|
- .gitignore
|
102
102
|
- .yardopts
|
103
|
+
- CHANGELOG.md
|
103
104
|
- Gemfile
|
104
105
|
- LICENSE.txt
|
105
106
|
- README.md
|
106
|
-
- REF
|
107
107
|
- Rakefile
|
108
108
|
- TODO
|
109
109
|
- beaneater.gemspec
|
@@ -147,18 +147,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
147
147
|
- - ! '>='
|
148
148
|
- !ruby/object:Gem::Version
|
149
149
|
version: '0'
|
150
|
-
segments:
|
151
|
-
- 0
|
152
|
-
hash: -2674763772608009517
|
153
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
151
|
none: false
|
155
152
|
requirements:
|
156
153
|
- - ! '>='
|
157
154
|
- !ruby/object:Gem::Version
|
158
155
|
version: '0'
|
159
|
-
segments:
|
160
|
-
- 0
|
161
|
-
hash: -2674763772608009517
|
162
156
|
requirements: []
|
163
157
|
rubyforge_project:
|
164
158
|
rubygems_version: 1.8.24
|
data/REF
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# Summary of what this does
|
2
|
-
#
|
3
|
-
# @!attribute [r] count
|
4
|
-
# @param [type] Name description
|
5
|
-
# @option name [Types] option_key (default_value) description
|
6
|
-
# @yield [a, b, c] Gives 3 random numbers to the block
|
7
|
-
# @return [type] description
|
8
|
-
# @raise [Types] description
|
9
|
-
# @example
|
10
|
-
# something.foo # => "test"
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
# Summary of what this does
|
15
|
-
#
|
16
|
-
# @param [type] Name description
|
17
|
-
# @option name [Types] option_key (default_value) description
|
18
|
-
# @yield [a, b, c] Gives 3 random numbers to the block
|
19
|
-
# @return [type] description
|
20
|
-
# @raise [Types] description
|
21
|
-
# @example
|
22
|
-
# something.foo # => "test"
|
23
|
-
#
|