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 ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
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,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'kestrelrb'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -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