beaneater 0.1.0 → 0.1.1
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.
- 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
|
-
#
|