Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial implementation

  • Loading branch information...
commit bc9bb08881c1efdd42ee0827d6720461d282f169 0 parents
@aeden authored
21 MIT_LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2004-2009 David Heinemeier Hansson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
62 README
@@ -0,0 +1,62 @@
+= ActiveQueue
+
+ActiveQueue provides a standard interface for sending messages to and
+receiving messages from message queues.
+
+The following adapters are included:
+
+* MemoryAdapter for a simple in-memory queue.
+* BeanstalkAdapter to communicate with one or more beanstalkd servers.
+
+
+== Usage Inside Rails
+
+
+When using ActiveQueue inside of Rails you can set up a configuration file
+in config/queue.yml like this:
+
+ development:
+ adapter: memory
+
+ production:
+ adapter: beanstalk
+
+And then you can get access to a named queue from the QueueProvider class:
+
+ queue = ActiveQueue::QueueProvider.queue('my_queue')
+ queue.send(message)
+
+Receiving messages works the same way:
+
+ queue = ActiveQueue::QueueProvider.queue('my_queue')
+ queue.receive(message)
+
+== Usage Outside of Rails
+
+A simple usage of the memory queue, outside of Rails, might look like this:
+
+ require 'active_queue'
+ queue = ActiveQueue::QueueProvider.queue('my_queue')
+ queue.send(message)
+
+ # another process
+ message = queue.recieve
+
+If you want to use a particular queue adapter:
+
+ require 'active_queue'
+ ActiveQueue::QueueProvider.initialize_adapter('beanstalk')
+ queue.send(message)
+
+ # another process
+ message = queue.recieve
+
+You can also specify configuration information for the adapter:
+
+ require 'active_queue'
+ configuration = {:hosts => ['192.168.1.1:11300','192.168.1.2:11300']}
+ ActiveQueue::QueueProvider.initialize_adapter('beanstalk', configuration)
+ queue.send(message)
+
+ # another process
+ message = queue.recieve
12 RUNNING_UNIT_TESTS
@@ -0,0 +1,12 @@
+== Running with Rake
+
+The easiest way to run the unit tests is through Rake. The default task runs
+the entire test suite for all classes. For more information, checkout the
+full array of rake tasks with "rake -T"
+
+Rake can be found at http://rake.rubyforge.org
+
+== Running Beanstalk Tests
+
+To run the beanstalk tests you must have beanstalkd running and accessible on
+localhost and 127.0.0.1 (which is usually mapped as localhost anyhow).
54 Rakefile
@@ -0,0 +1,54 @@
+dir = File.dirname(__FILE__)
+require "#{dir}/lib/active_queue/version"
+
+PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
+PKG_NAME = 'activequeue'
+PKG_VERSION = ActiveQueue::VERSION::STRING + PKG_BUILD
+PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
+RELEASE_NAME = "REL #{PKG_VERSION}"
+
+
+require 'rake/testtask'
+
+task :default => :test
+
+Rake::TestTask.new do |t|
+ t.libs << ["#{dir}/test", "#{dir}/lib"]
+ t.test_files = Dir.glob("#{dir}/test/**/*_test.rb").sort
+ t.verbose = true
+ t.warning = true
+ t.ruby_opts = ['-rubygems']
+end
+
+namespace :test do
+ task :isolated do
+ ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
+ Dir.glob("#{dir}/test/**/*_test.rb").all? do |file|
+ system(ruby, '-w', "-I#{dir}/lib", "-I#{dir}/test", file)
+ end or raise "Failures"
+ end
+end
+
+
+require 'rake/rdoctask'
+
+# Generate the RDoc documentation
+Rake::RDocTask.new do |rdoc|
+ rdoc.rdoc_dir = "#{dir}/doc"
+ rdoc.title = "Active Queue"
+ rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
+ rdoc.rdoc_files.include("#{dir}/README", "#{dir}/CHANGES")
+ rdoc.rdoc_files.include("#{dir}/lib/**/*.rb")
+end
+
+
+require 'rake/packagetask'
+require 'rake/gempackagetask'
+
+spec = eval(File.read("#{dir}/activequeue.gemspec"))
+
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+end
16 activequeue.gemspec
@@ -0,0 +1,16 @@
+Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = "activequeue"
+ s.version = "3.0.pre"
+ s.date = "2009-11-23"
+ s.summary = "Queue interface used by the Rails framework."
+ s.description = %q{Standard queue interface so Rails applications can send messages to queues}
+
+ s.files = Dir['CHANGELOG', 'README', 'lib/**/*']
+ s.require_path = 'lib'
+ s.has_rdoc = true
+
+ s.author = "Anthony Eden"
+ s.email = "anthonyeden@gmail.com"
+ s.homepage = "http://www.rubyonrails.org"
+end
41 lib/active_queue.rb
@@ -0,0 +1,41 @@
+#--
+# Copyright (c) 2004-2009 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+$:.unshift(activesupport_path) if File.directory?(activesupport_path)
+require 'active_support'
+require 'active_support/inflector'
+require 'active_support/json'
+
+# ActiveQueue provides a common interface to message queue systems for
+# use inside of Rails applications.
+module ActiveQueue
+ autoload :VERSION, 'active_queue/version'
+ autoload :QueueProvider, 'active_queue/queue_provider'
+ module QueueAdapters
+ autoload :AbstractProvider, 'active_queue/queue_adapters/abstract_provider'
+ autoload :AbstractQueueAdapter, 'active_queue/queue_adapters/abstract_queue_adapter'
+ end
+end
+
+I18n.load_path << File.dirname(__FILE__) + '/active_queue/locale/en.yml'
13 lib/active_queue/queue_adapters/abstract_provider.rb
@@ -0,0 +1,13 @@
+module ActiveQueue #:nodoc:
+ module QueueAdapters #:nodoc:
+ # Internal abstract base for provider implementations.
+ class AbstractProvider
+ def initialize(configuration={})
+ @configuration = configuration
+ end
+ def queues
+ @queues ||= {}
+ end
+ end
+ end
+end
21 lib/active_queue/queue_adapters/abstract_queue_adapter.rb
@@ -0,0 +1,21 @@
+module ActiveQueue #:nodoc:
+ module QueueAdapters #:nodoc:
+ # An abstract interface that queues must implement.
+ class AbstractQueueAdapter
+ # Send a message to the queue
+ def send(message)
+ raise NotImplementedError
+ end
+
+ # Receive the next message in the queue
+ def receive
+ raise NotImplementedError
+ end
+
+ # Return the approximate queue size
+ def size
+ raise NotImplementedError
+ end
+ end
+ end
+end
55 lib/active_queue/queue_adapters/beanstalk_adapter.rb
@@ -0,0 +1,55 @@
+begin
+ require 'beanstalk-client'
+rescue LoadError
+ raise "Beanstalk-client not available."
+end
+
+module ActiveQueue #:nodoc:
+ module QueueAdapters #:nodoc:
+ class BeanstalkProvider < AbstractProvider #:nodoc:
+ def queue(name)
+ queues[name] ||= BeanstalkAdapter.new({
+ :name => name, :hosts => @configuration[:hosts]
+ })
+ end
+ end
+ # A queue adapter for Beanstalk.
+ class BeanstalkAdapter < AbstractQueueAdapter
+ # Initialize the Beanstalk adapter.
+ #
+ # Options:
+ # * <tt>:name</tt>: The name of the queue. The name defaults to 'default'
+ # *<tt>:hosts</tt>: An array of host:port strings where beanstalkd is running.
+ # Defaults to ['localhost:11300']
+ def initialize(options={})
+ # beanstalk does not like underscores in tube names
+ @name = (options[:name] ||= 'default').gsub(/_/, '-')
+ @hosts = options[:hosts] ||= ['localhost:11300']
+ end
+
+ # Send a message to the beanstalk queue.
+ def send(message)
+ beanstalk.put(message)
+ end
+
+ # Receive the next message from the beanstalk queue.
+ def receive
+ visibility = 30
+ message = beanstalk.reserve(visibility)
+ body = message.body
+ message.delete
+ body
+ end
+
+ # Get the approximate queue size
+ def size
+ beanstalk.stats_tube(@name)['current-jobs-ready']
+ end
+
+ protected
+ def beanstalk
+ @beanstalk ||= Beanstalk::Pool.new(@hosts, @name)
+ end
+ end
+ end
+end
25 lib/active_queue/queue_adapters/memory_adapter.rb
@@ -0,0 +1,25 @@
+module ActiveQueue #:nodoc:
+ module QueueAdapters #:nodoc:
+ class MemoryProvider < AbstractProvider #:nodoc:
+ def queue(name)
+ queues[name] ||= MemoryAdapter.new({:name => name})
+ end
+ end
+ # A simple in-memory queue.
+ class MemoryAdapter < AbstractQueueAdapter
+ def initialize(options={})
+ @name = options[:name] ||= 'default'
+ @queue = []
+ end
+ def send(message)
+ @queue.push(message)
+ end
+ def receive
+ @queue.shift
+ end
+ def size
+ @queue.length
+ end
+ end
+ end
+end
36 lib/active_queue/queue_provider.rb
@@ -0,0 +1,36 @@
+module ActiveQueue #:nodoc:
+ # A queue provider will give back a named queue using whatever queue adapter
+ # was created at initialization.
+ class QueueProvider
+ # Get the named queue
+ def self.queue(name)
+ queue_adapter.queue(name)
+ end
+
+ # TODO: The methods below really should be for internal use only.
+
+ # Initialize the adpater. Expects a configurations Hash with a top level key
+ # that matches RAILS_ENV.
+ def self.initialize(configurations)
+ configuration = configurations[RAILS_ENV]
+ load_adapter(configuration['adapter'] || 'memory', configuration)
+ end
+
+ # Initialize the given named adapter.
+ def self.initialize_adapter(adapter_name, configuration={})
+ @queue_adapter = load_adapter(adapter_name, configuration)
+ end
+
+ # Load the named adapter. This will return an instance of the adapter.
+ def self.load_adapter(adapter_name, configuration={})
+ require "active_queue/queue_adapters/#{adapter_name}_adapter"
+ adapter_provider = "#{adapter_name}_provider".camelize
+ ActiveQueue::QueueAdapters.const_get(adapter_provider).new(configuration)
+ end
+
+ # Get a queue adapter instance
+ def self.queue_adapter
+ @queue_adapter ||= load_adapter('memory')
+ end
+ end
+end
9 lib/active_queue/version.rb
@@ -0,0 +1,9 @@
+module ActiveQueue
+ module VERSION #:nodoc:
+ MAJOR = 3
+ MINOR = 0
+ TINY = "pre"
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
2  test/helper.rb
@@ -0,0 +1,2 @@
+require 'test/unit'
+require 'active_queue'
32 test/queue_adapters/beanstalk_adapter_test.rb
@@ -0,0 +1,32 @@
+require 'helper'
+
+class BeanstalkAdapterTest < Test::Unit::TestCase
+ def message
+ {:x => 'x'}.to_json
+ end
+
+ def test_send_and_recieve
+ queue = ActiveQueue::QueueProvider.load_adapter('beanstalk').queue('a_queue')
+ queue.send(message)
+ assert_equal message, queue.receive
+ end
+ def test_size
+ queue = ActiveQueue::QueueProvider.load_adapter('beanstalk').queue('a_queue')
+ assert_equal 0, queue.size
+ queue.send(message)
+ assert_equal 1, queue.size
+ queue.send(message)
+ assert_equal 2, queue.size
+ queue.receive
+ assert_equal 1, queue.size
+ queue.receive
+ assert_equal 0, queue.size
+ end
+ def test_configuration
+ configuration = {:hosts => ['127.0.0.1:11300']}
+ adapter = ActiveQueue::QueueProvider.load_adapter('beanstalk', configuration)
+ queue = adapter.queue('a_queue')
+ queue.send(message)
+ assert_equal message, queue.receive
+ end
+end
23 test/queue_adapters/memory_adapter_test.rb
@@ -0,0 +1,23 @@
+require 'helper'
+
+class MemoryAdapterTest < Test::Unit::TestCase
+ def test_send_and_recieve
+ message = {:x => 'x'}
+ queue = ActiveQueue::QueueProvider.load_adapter('memory').queue('a_queue')
+ queue.send(message)
+ assert_equal message, queue.receive
+ end
+ def test_size
+ message = {:x => 'x'}
+ queue = ActiveQueue::QueueProvider.load_adapter('memory').queue('a_queue')
+ assert_equal 0, queue.size
+ queue.send(message)
+ assert_equal 1, queue.size
+ queue.send(message)
+ assert_equal 2, queue.size
+ queue.receive
+ assert_equal 1, queue.size
+ queue.receive
+ assert_equal 0, queue.size
+ end
+end
12 test/queue_provider_test.rb
@@ -0,0 +1,12 @@
+require 'helper'
+
+class QueueProviderTest < Test::Unit::TestCase
+ def test_defaults
+ message = {:x => 'x'}
+ queue = ActiveQueue::QueueProvider.queue('a_queue')
+ assert_equal ActiveQueue::QueueAdapters::MemoryAdapter, queue.class
+ queue.send(message)
+ assert_equal message, queue.receive
+ assert_equal nil, queue.receive
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.