beanstalk_farmer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ doc/
3
+ .yardoc/
4
+ pkg/*.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ #
4
+ # The following is cribbed directly from the rvm-site project. It's a more
5
+ # convenient way of ensuring we're using the correct gemset, or initializing it
6
+ # if need be.
7
+ #
8
+
9
+ ruby_name="ruby-1.9.2"
10
+ gemset_name="farmer"
11
+ environment_id="$ruby_name@$gemset_name"
12
+
13
+ #
14
+ # First we attempt to load the desired environment directly from the environment
15
+ # file, this is very fast and efficient compared to running through the entire
16
+ # CLI and selector. If you want feedback on which environment was used then
17
+ # insert the word 'use' after --create as this triggers verbose mode.
18
+ #
19
+
20
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] ; then
22
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
23
+ else
24
+ # If the environment file has not yet been created, use the RVM CLI to select.
25
+ rvm --create use "$environment_id"
26
+ fi
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --no-private
2
+ --title "Farmer: a Beanstalk Job Queue Gem"
3
+ lib/**/*.rb -
4
+ README.md
5
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ group :documentation do
5
+ gem "yard", "~> 0.6.8"
6
+ gem "bluecloth"
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 James F. Herdman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Beanstalk Farmer
2
+
3
+ Farmer is a simple library that helps you manage your Beanstalk job queue. Its
4
+ API is heavily inspired by [Stalker](https://github.com/han/stalker), to help
5
+ you get done as quickly as possible, but whilst allowing you to use plain old
6
+ Ruby classes to ensure testability.
7
+
8
+ ## Setting up Jobs
9
+
10
+ Jobs are handled by any object whose instances respond to a `#call` method, à
11
+ la Rack (e.g. `Proc`s, `procs`s). The payload of the job will be passed into
12
+ the arguments of this method. Bear in mind that the payload for a Beanstalk job
13
+ is de-serialized JSON.
14
+
15
+ ### Example
16
+
17
+ BeanstalkFarmer::Runner.register_handlers do
18
+ # You can use objects
19
+ tube 'email.welcome_message', WelcomeMessageHandler
20
+
21
+ # You can use Procs
22
+ tube 'push.message', Proc.new { |args| PushService.send_message(args) }
23
+ end
24
+
25
+ BeanstalkFarmer::Runner.run!
26
+
27
+ ## Configuration
28
+
29
+ Easy as pie! See `BeanstalkFarmer::Config` for all available options.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ require 'bundler/setup'
3
+ require 'bundler/gem_helper'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.rspec_opts = %w[--color]
11
+ t.verbose = false
12
+ end
13
+
14
+ require 'yard'
15
+ require 'yard/rake/yardoc_task'
16
+
17
+ YARD::Rake::YardocTask.new do |t|
18
+ # Options managed by .yardopts
19
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $:.unshift(lib) unless $:.include?(lib)
4
+
5
+ require 'beanstalk_farmer/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'beanstalk_farmer'
9
+ s.version = BeanstalkFarmer::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ['James Herdamn']
12
+ s.email = ['james.herdman@me.com']
13
+ s.homepage = 'https://github.com/jherdman/beanstalk_farmer'
14
+ s.summary = 'A nice little kit to manage a Beanstalk job queue'
15
+ s.description = 'Farmer is a nice little kit to manage a Beanstalk job queue'
16
+
17
+ s.required_rubygems_version = '>= 1.3.6'
18
+ s.rubyforge_project = 'farmer'
19
+
20
+ s.add_dependency 'beanstalk-client', ['~> 1.1.0']
21
+ s.add_dependency 'multi_json', ['~> 1.0.2']
22
+
23
+ s.add_development_dependency 'rake', ['~> 0.8.7']
24
+ s.add_development_dependency 'rspec', ['~> 2.6']
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
28
+ s.require_path = ['lib']
29
+ end
data/example/echo.rb ADDED
@@ -0,0 +1,18 @@
1
+ ##
2
+ # This is a simple echo worker example. To use this, you must have the Farmer
3
+ # gem installed, or built.
4
+
5
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
6
+ require 'farmer'
7
+
8
+ BeanstalkFarmer::Runner.register_handlers do
9
+ tube 'echo.small_proc', proc { |args| BeanstalkFarmer.logger.info "Small proc says: #{args.inspect}" }
10
+ tube 'echo.big_proc', Proc.new { |args| BeanstalkFarmer.logger.info "Big Proc says: #{args.inspect}" }
11
+ end
12
+
13
+ trap 'INT' do
14
+ puts "\rExiting"
15
+ exit
16
+ end
17
+
18
+ BeanstalkFarmer::Runner.run!
@@ -0,0 +1,53 @@
1
+ module BeanstalkFarmer
2
+ # Manages configuration settings and defaults.
3
+ #
4
+ # @example
5
+ # BeanstalkFarmer::Config.logger = Rails.logger
6
+ # BeanstalkFarmer::Config.json_engine = :yajl
7
+ module Config
8
+ extend self
9
+
10
+ DEFAULT_HOST = '0.0.0.0'
11
+ DEFAULT_PORT = 11300
12
+
13
+ attr_accessor :settings
14
+ @settings = {}
15
+
16
+ # Define a configuration option with a default.
17
+ #
18
+ # @example Define the option.
19
+ # Config.option(:persist_in_safe_mode, :default => false)
20
+ #
21
+ # @param [Symbol] name The name of the configuration option.
22
+ # @param [Hash] options Extras for the option.
23
+ #
24
+ # @option options [Object] :default The default value.
25
+ #
26
+ # @note Copied from Mongoid. Thank you!
27
+ #
28
+ # @private
29
+ def option(name, options = {})
30
+ define_method(name) do
31
+ settings.has_key?(name) ? settings[name] : options[:default]
32
+ end
33
+ define_method("#{name}=") { |value| settings[name] = value }
34
+ define_method("#{name}?") { send(name) }
35
+ end
36
+
37
+ option :host, default: DEFAULT_HOST
38
+
39
+ option :port, default: DEFAULT_PORT
40
+
41
+ option :logger, default: ::Logger.new($stdout)
42
+
43
+ # @see MultiJson.default_engine
44
+ def json_engine
45
+ MultiJson.engine
46
+ end
47
+
48
+ # @see MultiJson.engine=
49
+ def json_engine=(json_engine)
50
+ MultiJson.engine = json_engine
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,14 @@
1
+ module BeanstalkFarmer
2
+ # @private Provides a clean slate object that we can safely instance eval on.
3
+ class DSL
4
+ def tube(tube_name, job_handler)
5
+ Job.handler_pool[tube_name] = job_handler
6
+ end
7
+
8
+ def self.execute!(&block)
9
+ new.tap do |dsl|
10
+ dsl.instance_eval(&block)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ require 'multi_json'
2
+ require 'timeout'
3
+
4
+ module BeanstalkFarmer
5
+ class Job
6
+ # Raised when a job cannot complete in time
7
+ class OutOfTimeError < Timeout::Error; end
8
+
9
+ attr_accessor :name, :args, :job
10
+
11
+ # @param [Beanstalk::Job] job A Beanstalk job that has been reserved to be
12
+ # worked upon
13
+ def initialize(job)
14
+ self.job = job
15
+ set_name_and_arguments
16
+ end
17
+
18
+ # Performs work for this job
19
+ def work
20
+ # Stalker, the inspiration for this project, subtracted 1 from the job's
21
+ # TTR value. I'm not sure why at this point in time. Maybe to compensate
22
+ # for Job setup time.
23
+ Timeout.timeout(job.ttr) do
24
+ handler = self.class.handler_pool[name]
25
+ handler.call(args)
26
+ end
27
+ rescue Timeout::Error
28
+ raise OutOfTimeError, "#{name} could not finish in #{job.ttr} seconds"
29
+ ensure
30
+ job.delete
31
+ end
32
+
33
+ # A pool of job handlers that can work on jobs in our queue
34
+ #
35
+ # @param [Boolean] reset (false) When true, our collection of job handlers
36
+ # will be purged from memory
37
+ #
38
+ # @return [Hash] the collection of job handlers
39
+ def self.handler_pool(reset=false)
40
+ @pool = nil if reset
41
+ @pool ||= Hash.new
42
+ end
43
+
44
+ private
45
+
46
+ def set_name_and_arguments
47
+ self.name, self.args = MultiJson.decode(job.body)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ require 'singleton'
2
+
3
+ module BeanstalkFarmer
4
+ # Maps tube names to job handlers, and manages the run loop
5
+ class Runner
6
+ include Singleton
7
+
8
+ # @see Farmer::Job.handler_pool
9
+ def handler_pool
10
+ Job.handler_pool
11
+ end
12
+
13
+ # @return [Farmer::BeanstalkService] a connection to the Beanstalk queue
14
+ def service
15
+ @service ||= Service.new
16
+ end
17
+
18
+ # Prepares tubes for watching
19
+ def prep_tubes
20
+ service.prep(handler_pool.keys)
21
+ end
22
+
23
+ # Reserves a job, and works it
24
+ def reserve_and_work_job
25
+ job = service.reserve
26
+ job.work
27
+ end
28
+
29
+ # Runs a loop looking for jobs to reserve and run
30
+ def work_jobs
31
+ loop { reserve_and_work_job }
32
+ end
33
+
34
+ # @yield block A DSL to define jobs for your queue
35
+ #
36
+ # @example
37
+ # Farmer::Runner.register_handlers do
38
+ # tube 'sms', proc { |args| puts args }
39
+ # tube 'mine', Proc.new { |args| puts args }
40
+ # end
41
+ def self.register_handlers(&block)
42
+ DSL.execute!(&block)
43
+ end
44
+
45
+ # Looks for jobs to reserve, and applies handlers to them
46
+ def self.run!
47
+ instance.prep_tubes
48
+ instance.work_jobs
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,83 @@
1
+ require 'beanstalk-client'
2
+ require 'multi_json'
3
+
4
+ module BeanstalkFarmer
5
+ ##
6
+ # Provides an abstraction against our Beanstalk client to buffer us against
7
+ # changes in their API.
8
+ #
9
+ # @todo Abstract all 3rd party errors
10
+ # @todo Catch all 3rd party errors, and re-raise our own
11
+ #
12
+ # @private
13
+ class Service
14
+ DEFAULT_DELAY = 0
15
+ DEFAULT_PRIORITY = 65536
16
+ DEFAULT_TTR = 120
17
+
18
+ # Raised when we cannot connect to the Beanstalk queue
19
+ class NotConnectedError < Beanstalk::NotConnected; end
20
+
21
+ attr_accessor :uri
22
+
23
+ # Sets the URI of your Beanstalk queue.
24
+ #
25
+ # @param [String] host (DEFAULT_HOST) the host name to of your Beanstalk queue
26
+ #
27
+ # @param [String] port (DEFAULT_PORT) the port that your Beanstalk queue is on
28
+ def initialize(host=Config.host, port=Config.port)
29
+ self.uri = build_uri(host, port)
30
+ end
31
+
32
+ # @return [Beanstalk::Pool] a connection to Beanstalk
33
+ def connection
34
+ @connection ||= Beanstalk::Pool.new([uri])
35
+ end
36
+
37
+ # Closes the Beanstalk connection
38
+ #
39
+ # @return [nil] Nothing. Absolutely nothing.
40
+ def close
41
+ @connection.close
42
+ @connection = nil
43
+ end
44
+
45
+ # @param [Array<String>] tube_names The tube names to be watched
46
+ def prep(tube_names)
47
+ watch_tubes(tube_names)
48
+ ignore_unwatched_tubes(tube_names)
49
+ end
50
+
51
+ # @param [Array<String>] tube_names The tube names to be watched
52
+ def watch_tubes(tube_names)
53
+ tube_names.each { |tube_name| connection.watch(tube_name) }
54
+ end
55
+
56
+ # Ignores any tubes that aren't of interest, excluding the default tube.
57
+ def ignore_unwatched_tubes(watched_tube_names)
58
+ connection.list_tubes_watched.values do |tube_name|
59
+ connection.ignore(tube_name) unless watched_tube_names.include?(tube_name)
60
+ end
61
+ end
62
+
63
+ # Helper method. Used when testing to see if our queue works
64
+ def enqueue(tube_name, args={})
65
+ connection.use(tube_name)
66
+ connection.put MultiJson.encode([tube_name, args]), DEFAULT_PRIORITY, DEFAULT_DELAY, DEFAULT_TTR
67
+ end
68
+
69
+ # @param [Integer, nil] timeout When nil, a job is reserved indefinitely,
70
+ # otherwise for the number of seconds provided
71
+ #
72
+ # @return [Farmer::Job] a Farmer Job to work
73
+ def reserve(timeout=nil)
74
+ Job.new(connection.reserve(timeout))
75
+ end
76
+
77
+ private
78
+
79
+ def build_uri(host, port)
80
+ [host, port].join(':')
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,3 @@
1
+ module BeanstalkFarmer
2
+ VERSION = "0.1.0"
3
+ end
data/lib/farmer.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'logger'
2
+
3
+ ##
4
+ # Automatically loads classes as needed, provides logger, etc.
5
+ module BeanstalkFarmer
6
+ autoload :Config, 'beanstalk_farmer/config'
7
+ autoload :Service, 'beanstalk_farmer/service'
8
+ autoload :DSL, 'beanstalk_farmer/dsl'
9
+ autoload :Job, 'beanstalk_farmer/job'
10
+ autoload :Runner, 'beanstalk_farmer/runner'
11
+
12
+ # @param [String] host The host name where your beanstalkd connection is
13
+ # located. Defaults to `DEFAULT_PORT`.
14
+ #
15
+ # @param [#to_s] port The port number where your beanstalkd connection may
16
+ # be accessed. Defaults to `DEFAULT_PORT`.
17
+ def self.connection(host=Config.host, port=Config.port)
18
+ @service ||= Service.new(host, port)
19
+ @service.connection
20
+ end
21
+
22
+ # Close Beanstalk connection
23
+ def self.close_connection
24
+ @service.close
25
+ @service = nil
26
+ end
27
+
28
+ # @return [Logger] the logger, defaulting to a STDOUT logger
29
+ def self.logger
30
+ @logger ||= Config.logger
31
+ @logger
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer::Config do
4
+ describe ".option" do
5
+ before(:all) do
6
+ described_class.option(:test_setting, default: true)
7
+ end
8
+
9
+ it "creates a getter for an option" do
10
+ described_class.should respond_to(:test_setting)
11
+ end
12
+
13
+ it "creates a setter for the option" do
14
+ described_class.should respond_to(:test_setting=)
15
+ end
16
+
17
+ it "creates a conditional for the option" do
18
+ described_class.should respond_to(:test_setting?)
19
+ end
20
+
21
+ it "allows the setting of a default value" do
22
+ described_class.test_setting.should == true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer::DSL do
4
+ describe '#tube' do
5
+ let(:tube_name) { 'my_tube' }
6
+ let(:handler) { Proc.new { |args| args } }
7
+
8
+ after(:each) do
9
+ BeanstalkFarmer::Job.handler_pool(true)
10
+ end
11
+
12
+ it 'correctly adds job handlers for some tube' do
13
+ subject.tube(tube_name, handler)
14
+ BeanstalkFarmer::Job.handler_pool[tube_name].should == handler
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer::Job do
4
+ let(:job) {
5
+ double('job', body: "[\"bacon\",{\"msg\":\"Hello\"}]", name: 'bacon', args: { 'msg' => 'Hello' }, ttr: 56, delete: true)
6
+ }
7
+
8
+ describe '.new' do
9
+ it 'sets the job' do
10
+ described_class.new(job).job.should == job
11
+ end
12
+
13
+ it 'decodes the name of the job' do
14
+ described_class.new(job).name.should == job.name
15
+ end
16
+
17
+ it 'decodes the arguments for the job' do
18
+ described_class.new(job).args.should == job.args
19
+ end
20
+ end
21
+
22
+ describe '.handler_pool' do
23
+ it 'is a Hash of job handlers' do
24
+ described_class.handler_pool.should be_a_kind_of(Hash)
25
+ end
26
+
27
+ it 'can reset the Hash of job hanlders' do
28
+ described_class.handler_pool['bacon'] = lambda { |args| args }
29
+ described_class.handler_pool(true)
30
+ described_class.handler_pool.should be_empty
31
+ end
32
+ end
33
+
34
+ describe '#work' do
35
+ let(:handler) { proc { |args| args } }
36
+
37
+ subject { described_class.new(job) }
38
+
39
+ before(:each) do
40
+ described_class.handler_pool[job.name] = handler
41
+ end
42
+
43
+ it 'performs some work for the handler' do
44
+ subject.work.should == job.args
45
+ end
46
+
47
+ it 'times out if the job has run out of time' do
48
+ Timeout.should_receive(:timeout).with(job.ttr) { raise Timeout::Error }
49
+ expect { subject.work }.to raise_error(BeanstalkFarmer::Job::OutOfTimeError)
50
+ end
51
+
52
+ it 'deletes the job' do
53
+ subject.job.should_receive(:delete)
54
+ subject.work
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer::Runner do
4
+ subject { described_class.instance }
5
+
6
+ it 'is a singleton' do
7
+ described_class.included_modules.should include(Singleton)
8
+ end
9
+
10
+ its(:service) { should be_a_kind_of(BeanstalkFarmer::Service) }
11
+
12
+ describe '#handler_pool' do
13
+ it 'is the job handler pool' do
14
+ BeanstalkFarmer::Job.should_receive(:handler_pool)
15
+ subject.handler_pool
16
+ end
17
+ end
18
+
19
+ describe '#prep_tubes' do
20
+ it 'prepares tubes for watching' do
21
+ subject.service.should_receive(:prep).with(subject.handler_pool.keys)
22
+ subject.prep_tubes
23
+ end
24
+ end
25
+
26
+ describe '#reserve_and_work_job' do
27
+ let(:job) { double('Farmer::Job', work: true) }
28
+
29
+ before(:each) do
30
+ subject.stub_chain(:service, :reserve) { job }
31
+ end
32
+
33
+ it 'reserves a job' do
34
+ subject.service.should_receive(:reserve) { job }
35
+ subject.reserve_and_work_job
36
+ end
37
+
38
+ it 'works the job' do
39
+ job.should_receive(:work)
40
+ subject.reserve_and_work_job
41
+ end
42
+ end
43
+
44
+ describe '.run!' do
45
+ before(:each) do
46
+ subject.stub(:prep_tubes)
47
+ subject.stub(:work_jobs)
48
+ end
49
+
50
+ it 'prepares tubes for watching' do
51
+ subject.should_receive(:prep_tubes)
52
+ described_class.run!
53
+ end
54
+
55
+ it 'works jobs' do
56
+ subject.should_receive(:work_jobs)
57
+ described_class.run!
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer::Service do
4
+ describe '.new' do
5
+ it 'sets the `uri` attribute' do
6
+ described_class.new.uri.should =~ /\A#{BeanstalkFarmer::Config.host}:#{BeanstalkFarmer::Config.port}\z/
7
+ end
8
+ end
9
+
10
+ describe '#connection' do
11
+ after(:each) do
12
+ subject.close
13
+ end
14
+
15
+ it 'establishes a connection to Beanstalk' do
16
+ expect {
17
+ subject.connection.put 'Hello'
18
+ }.to_not raise_error(BeanstalkFarmer::Service::NotConnectedError)
19
+ end
20
+ end
21
+
22
+ describe '#close' do
23
+ it 'closes the Beanstalk connection' do
24
+ connection = subject.connection # ensure we're connected
25
+ subject.close
26
+ connection.open_connections.should be_empty
27
+ end
28
+ end
29
+
30
+ describe '#watch_tubes' do
31
+ it 'adds a tube to the list of watched tubes' do
32
+ subject.watch_tubes(%w[bacon])
33
+ subject.connection.list_tubes_watched.should have_tube_named('bacon')
34
+ end
35
+ end
36
+
37
+ describe '#ignore_unwatched_tubes' do
38
+ it 'ignores tubes that are not being watched' do
39
+ pending 'a creative way to test this problem'
40
+ end
41
+ end
42
+
43
+ describe '#reserve' do
44
+ let(:job) {
45
+ double('job', body: "[\"bacon\",{\"msg\":\"Hello\"}]", name: 'bacon', args: { 'msg' => 'Hello' }, ttr: 56)
46
+ }
47
+
48
+ before(:each) do
49
+ subject.connection.stub(:reserve) { job }
50
+ end
51
+
52
+ it 'builds a Farmer::Job' do
53
+ subject.reserve.should be_a_kind_of(BeanstalkFarmer::Job)
54
+ end
55
+
56
+ it 'reserves a job indefinitely' do
57
+ subject.connection.should_receive(:reserve).with(nil) { job }
58
+ subject.reserve
59
+ end
60
+
61
+ it 'reserves a job for the specified number of seconds' do
62
+ subject.connection.should_receive(:reserve).with(30) { job }
63
+ subject.reserve(30)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe BeanstalkFarmer do
4
+ describe '.connection' do
5
+ it 'initializes a new Beanstalk connection' do
6
+ described_class::Service.any_instance.should_receive(:connection)
7
+ described_class.connection
8
+ end
9
+ end
10
+
11
+ describe '.close_connection' do
12
+ before(:each) do
13
+ described_class::Service.any_instance.stub(:connection)
14
+ described_class::Service.any_instance.stub(:close)
15
+
16
+ described_class.connection # sets up a connection
17
+ end
18
+
19
+ it 'closes all connections to Beanstalk' do
20
+ described_class::Service.any_instance.should_receive(:close)
21
+ described_class.close_connection
22
+ end
23
+ end
24
+
25
+ its(:logger) { should be_a_kind_of(Logger) }
26
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'farmer'
4
+
5
+ Dir['./spec/support/**/*.rb'].each { |support_file| require support_file }
6
+
7
+ RSpec.configure do |config|
8
+ end
@@ -0,0 +1,7 @@
1
+ RSpec::Matchers.define :have_tube_named do |expected_tube_name|
2
+ match do |watched_tubes_hash|
3
+ watched_tubes_hash.values.flatten.include?(expected_tube_name)
4
+ end
5
+
6
+ diffable
7
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beanstalk_farmer
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - James Herdamn
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-16 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: beanstalk-client
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.0
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: multi_json
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.2
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rake
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.7
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: "2.6"
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ description: Farmer is a nice little kit to manage a Beanstalk job queue
61
+ email:
62
+ - james.herdman@me.com
63
+ executables: []
64
+
65
+ extensions: []
66
+
67
+ extra_rdoc_files: []
68
+
69
+ files:
70
+ - .gitignore
71
+ - .rspec
72
+ - .rvmrc
73
+ - .yardopts
74
+ - Gemfile
75
+ - LICENSE
76
+ - README.md
77
+ - Rakefile
78
+ - beanstalk_farmer.gemspec
79
+ - example/echo.rb
80
+ - lib/beanstalk_farmer/config.rb
81
+ - lib/beanstalk_farmer/dsl.rb
82
+ - lib/beanstalk_farmer/job.rb
83
+ - lib/beanstalk_farmer/runner.rb
84
+ - lib/beanstalk_farmer/service.rb
85
+ - lib/beanstalk_farmer/version.rb
86
+ - lib/farmer.rb
87
+ - spec/beanstalk_farmer/config_spec.rb
88
+ - spec/beanstalk_farmer/dsl_spec.rb
89
+ - spec/beanstalk_farmer/job_spec.rb
90
+ - spec/beanstalk_farmer/runner_spec.rb
91
+ - spec/beanstalk_farmer/service_spec.rb
92
+ - spec/beastalk_farmer_spec.rb
93
+ - spec/spec_helper.rb
94
+ - spec/support/have_tube_named.rb
95
+ has_rdoc: true
96
+ homepage: https://github.com/jherdman/beanstalk_farmer
97
+ licenses: []
98
+
99
+ post_install_message:
100
+ rdoc_options: []
101
+
102
+ require_paths:
103
+ - - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: -1506406479877648838
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.3.6
119
+ requirements: []
120
+
121
+ rubyforge_project: farmer
122
+ rubygems_version: 1.6.2
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: A nice little kit to manage a Beanstalk job queue
126
+ test_files: []
127
+