kestrelrb 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/kestrelrb.rb +134 -0
- data/test/helper.rb +10 -0
- data/test/test_kestrelrb.rb +80 -0
- metadata +74 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Kevin E. Hunt
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= kestrelrb
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Kevin E. Hunt. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "kestrelrb"
|
8
|
+
gem.summary = %Q{A Ruby interface to Kestrel queues}
|
9
|
+
gem.description = %Q{Kestrel is a queue server written in Scala that runs on the JVM and has a memcached wire API.}
|
10
|
+
gem.email = "kevin@kev.in"
|
11
|
+
gem.homepage = "http://github.com/kevn/kestrelrb"
|
12
|
+
gem.authors = ["Kevin E. Hunt"]
|
13
|
+
gem.add_dependency "memcache-client", ">= 1.7.5"
|
14
|
+
# gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "kestrelrb #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.0
|
data/lib/kestrelrb.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'memcache'
|
2
|
+
module Kestrel
|
3
|
+
|
4
|
+
class Queue
|
5
|
+
|
6
|
+
class Unsubscribe < StandardError; end
|
7
|
+
|
8
|
+
SLEEP_DELAY = 0.001 # Seconds to sleep when no messages in queue and GET timeout is 0
|
9
|
+
|
10
|
+
attr_reader :queue_name, :options
|
11
|
+
|
12
|
+
def initialize(queue_name, *args)
|
13
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
14
|
+
@options = validate_queue_options(opts)
|
15
|
+
@queue_name = queue_name
|
16
|
+
servers = args.empty? ? ['localhost:22133'] : args
|
17
|
+
# Instantiate Memcache client with the specified servers and a timeout of 2x the GET timeout
|
18
|
+
@kestrel = MemCache.new(servers, :timeout => timeout * 2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def drop
|
22
|
+
@kestrel.delete(queue_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def flush
|
26
|
+
raise NotImplementedError, "FLUSH command is not yet supported."
|
27
|
+
# @kestrel.flush
|
28
|
+
end
|
29
|
+
|
30
|
+
def flush_all
|
31
|
+
@kestrel.flush_all
|
32
|
+
end
|
33
|
+
|
34
|
+
def stats
|
35
|
+
@kestrel.stats
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_error(&block)
|
39
|
+
(@error_handlers ||= []) << block
|
40
|
+
end
|
41
|
+
|
42
|
+
def subscribe(&block)
|
43
|
+
loop do
|
44
|
+
msg = nil
|
45
|
+
begin
|
46
|
+
if msg = get
|
47
|
+
block.call(msg)
|
48
|
+
else
|
49
|
+
sleep SLEEP_DELAY if timeout != 0
|
50
|
+
end
|
51
|
+
rescue Unsubscribe => e
|
52
|
+
break
|
53
|
+
rescue StandardError => e
|
54
|
+
abort if reliable?
|
55
|
+
@error_handlers.each{ |b| b.call(e, msg) } if @error_handlers
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def enqueue(v)
|
61
|
+
@kestrel.set(queue_name, v)
|
62
|
+
end
|
63
|
+
|
64
|
+
def dequeue(raw = false)
|
65
|
+
@kestrel.get(get_key, raw)
|
66
|
+
end
|
67
|
+
alias get dequeue
|
68
|
+
|
69
|
+
def peek(raw = false)
|
70
|
+
@kestrel.get(peek_key, raw)
|
71
|
+
end
|
72
|
+
|
73
|
+
def abort
|
74
|
+
@kestrel.get(abort_key)
|
75
|
+
end
|
76
|
+
|
77
|
+
def timeout
|
78
|
+
options[:timeout]
|
79
|
+
end
|
80
|
+
|
81
|
+
def reliable?
|
82
|
+
options[:reliable]
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
def get_key
|
87
|
+
@get_key ||= reliable? ? close_open_key : plain_key
|
88
|
+
end
|
89
|
+
|
90
|
+
def plain_key
|
91
|
+
@plain_key ||= "#{queue_name}/t=#{timeout}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def peek_key
|
95
|
+
@peek_key ||= "#{queue_name}/peek"
|
96
|
+
end
|
97
|
+
|
98
|
+
def close_open_key
|
99
|
+
@close_open_key ||= "#{queue_name}/close/open/t=#{timeout}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def open_key
|
103
|
+
@open_key ||= "#{queue_name}/open/t=#{timeout}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def close_key
|
107
|
+
@close_key ||= close_key = "#{queue_name}/close"
|
108
|
+
end
|
109
|
+
|
110
|
+
def abort_key
|
111
|
+
@abort_key ||= abort_key = "#{queue_name}/abort"
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate_queue_options(opts)
|
115
|
+
options = default_options.merge(opts)
|
116
|
+
unknown_keys = (options.keys - valid_keys)
|
117
|
+
raise "Unknown queue options: #{unknown_keys.inspect}" unless unknown_keys.empty?
|
118
|
+
options
|
119
|
+
end
|
120
|
+
|
121
|
+
def valid_keys
|
122
|
+
[:reliable, :timeout]
|
123
|
+
end
|
124
|
+
|
125
|
+
def default_options
|
126
|
+
{
|
127
|
+
:reliable => true,
|
128
|
+
:timeout => 500, #ms
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/kestrelrb.rb'
|
3
|
+
require 'test/unit'
|
4
|
+
class ReliableQueueTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
QUEUE_NAME = 'test_queue'
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@q = Kestrel::Queue.new(QUEUE_NAME, :timeout => 100)
|
10
|
+
@q.drop
|
11
|
+
@q.on_error do |exception, msg|
|
12
|
+
puts "Exception: #{exception.class}: #{exception.message} (Message: #{msg})"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
@q.drop
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_empty
|
21
|
+
assert_equal nil, @q.get
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_enqueue_dequeue
|
25
|
+
s = random_string
|
26
|
+
@q.enqueue(s)
|
27
|
+
assert_equal s, @q.dequeue
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_peek
|
31
|
+
assert_equal nil, @q.dequeue
|
32
|
+
s = random_string
|
33
|
+
@q.enqueue(s)
|
34
|
+
assert_equal s, @q.peek
|
35
|
+
assert_equal s, @q.peek
|
36
|
+
assert_equal s, @q.dequeue
|
37
|
+
assert_equal nil, @q.dequeue
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_explicit_requeue
|
41
|
+
assert_equal nil, @q.get
|
42
|
+
s = random_string
|
43
|
+
@q.enqueue(s)
|
44
|
+
assert_equal s, @q.dequeue # First time
|
45
|
+
@q.abort # requeue
|
46
|
+
assert_equal s, @q.dequeue # Second time
|
47
|
+
assert_equal nil, @q.dequeue
|
48
|
+
end
|
49
|
+
|
50
|
+
# FIXME: This test depends on FIFO, even though Kestrel does not guarantee ordering
|
51
|
+
def test_subscribe
|
52
|
+
|
53
|
+
100.times do
|
54
|
+
@q.enqueue(random_string)
|
55
|
+
end
|
56
|
+
@q.enqueue("LAST MESSAGE")
|
57
|
+
|
58
|
+
results = []
|
59
|
+
@q.on_error do
|
60
|
+
assert_equal 100, results.size
|
61
|
+
end
|
62
|
+
|
63
|
+
@q.subscribe do |msg|
|
64
|
+
raise Kestrel::Queue::Unsubscribe if msg == "LAST MESSAGE"
|
65
|
+
results << msg
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_stats
|
71
|
+
stats = @q.stats
|
72
|
+
assert stats.is_a?(Hash)
|
73
|
+
assert stats['localhost:22133']['bytes_read'].is_a?(Numeric)
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
def random_string
|
78
|
+
"This is a test #{rand(10_000)}"
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kestrelrb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin E. Hunt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-29 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: memcache-client
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.5
|
24
|
+
version:
|
25
|
+
description: Kestrel is a queue server written in Scala that runs on the JVM and has a memcached wire API.
|
26
|
+
email: kevin@kev.in
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- lib/kestrelrb.rb
|
42
|
+
- test/helper.rb
|
43
|
+
- test/test_kestrelrb.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/kevn/kestrelrb
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A Ruby interface to Kestrel queues
|
72
|
+
test_files:
|
73
|
+
- test/helper.rb
|
74
|
+
- test/test_kestrelrb.rb
|