myobie-merb_queue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Nathan Herald
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.
@@ -0,0 +1,47 @@
1
+ merb_queue
2
+ ==========
3
+
4
+ <http://github.com/myobie/merb_queue>
5
+
6
+ Description
7
+ -----------
8
+
9
+ A persistent queue used to perform repetitive actions with many merb processes across many servers if needed.
10
+
11
+ Requirements
12
+ ------------
13
+
14
+ * merb-core
15
+ * sequel-core (if using db persistence)
16
+ * fiveruns-memcache-client (if using memcache persistence)
17
+
18
+ Install
19
+ -------
20
+
21
+ gem install myobie-merb_queue -s http://gems.github.com
22
+
23
+ License
24
+ -------
25
+
26
+ (The MIT License)
27
+
28
+ Copyright (c) 2008 Nathan Herald
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining
31
+ a copy of this software and associated documentation files (the
32
+ 'Software'), to deal in the Software without restriction, including
33
+ without limitation the rights to use, copy, modify, merge, publish,
34
+ distribute, sublicense, and/or sell copies of the Software, and to
35
+ permit persons to whom the Software is furnished to do so, subject to
36
+ the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be
39
+ included in all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
42
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require "spec/rake/spectask"
6
+
7
+ PLUGIN = "merb_queue"
8
+ NAME = "merb_queue"
9
+ GEM_VERSION = "0.0.1"
10
+ AUTHOR = "Nathan Herald"
11
+ EMAIL = "nathan@myobie.com"
12
+ HOMEPAGE = "http://github.com/myobie/merb_queue"
13
+ SUMMARY = "A persistent queue across multiple merb processes"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = NAME
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", 'TODO']
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+ s.add_dependency('merb-core', '>= 0.9.3')
27
+ s.require_path = 'lib'
28
+ s.autorequire = PLUGIN
29
+ s.files = %w(LICENSE README.markdown Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.gem_spec = spec
34
+ end
35
+
36
+ desc "install the plugin locally"
37
+ task :install => [:package] do
38
+ sh %{sudo gem install pkg/#{NAME}-#{VERSION}}
39
+ end
40
+
41
+ desc "create a gemspec file"
42
+ task :make_spec do
43
+ File.open("#{NAME}.gemspec", "w") do |file|
44
+ file.puts spec.to_ruby
45
+ end
46
+ end
47
+
48
+ namespace :jruby do
49
+
50
+ desc "Run :package and install the resulting .gem with jruby"
51
+ task :install => :package do
52
+ sh %{#{SUDO} jruby -S gem install pkg/#{NAME}-#{Merb::VERSION}.gem --no-rdoc --no-ri}
53
+ end
54
+
55
+ end
56
+
57
+ desc "Run the specs"
58
+ Spec::Rake::SpecTask.new("specs") do |t|
59
+ t.spec_opts = ["--format", "specdoc", "--colour"]
60
+ t.spec_files = Dir["spec/**/*_spec.rb"].sort
61
+ end
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ - More specs!
2
+ - Make it actually persistent using sqlite3
3
+ - Use PStore for persistence
4
+ - Use memcache for persistence
5
+ - Use starling for persistence
@@ -0,0 +1,45 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'logger'
5
+ require 'merb-core'
6
+
7
+ module MerbQueueError
8
+ class QueueEmpty < StandardError; end
9
+ class WrongQueueDatatype < StandardError; end
10
+ end
11
+
12
+ require 'merb_queue/base'
13
+ require 'merb_queue/queue'
14
+
15
+ module MerbQueue
16
+
17
+ def self.[](what)
18
+ MerbQueue::Base[what]
19
+ end
20
+
21
+ def self.register(name, &block)
22
+ MerbQueue::Base.register(name, &block)
23
+ end
24
+
25
+ def self.add(name, &block)
26
+ MerbQueue::Base.add(name, &block)
27
+ end
28
+
29
+ def self.all
30
+ MerbQueue::Base.all
31
+ end
32
+
33
+ def self.logger
34
+ MerbQueue::Base.logger
35
+ end
36
+
37
+ def self.delete(what)
38
+ MerbQueue::Base.delete(what)
39
+ end
40
+
41
+ end
42
+
43
+ Merb::BootLoader.after_app_loads do
44
+ require Merb.root / "config" / "queues.rb" if File.exists?(Merb.root / "config" / "queues.rb")
45
+ end
@@ -0,0 +1,38 @@
1
+ module MerbQueue
2
+
3
+ class Base
4
+ @@queues = {}
5
+ @@logger = Logger.new(Merb.root / "log" / "queue.log", 5, 512000)
6
+
7
+ def self.logger
8
+ @@logger
9
+ end
10
+
11
+ def self.register(name, &block)
12
+ logger.info "Registering #{name}..."
13
+ a = MerbQueue.add(name, &block)
14
+ a.start
15
+ end
16
+
17
+ def self.add(name, &block)
18
+ logger.info "Adding #{name}..."
19
+ a = MerbQueue::Queue.new(name, &block)
20
+ @@queues[name] = a
21
+ a
22
+ end
23
+
24
+ def self.[](what)
25
+ @@queues[what]
26
+ end
27
+
28
+ def self.all
29
+ @@queues
30
+ end
31
+
32
+ def self.delete(what)
33
+ @@queues.delete(what)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,130 @@
1
+ module MerbQueue
2
+
3
+ class Queue
4
+
5
+ attr_accessor :queue, :name, :running, :logger, :t, :wait_seconds, :max_attempts
6
+
7
+ def initialize(name, &block)
8
+ @queue = []
9
+ @running = false
10
+ @max_attempts = 3
11
+ @wait_seconds = 10
12
+ @name = name
13
+ @logger = MerbQueue::Base.logger
14
+ @work_to_be_done = block
15
+ end
16
+
17
+ def running?
18
+ @running
19
+ end
20
+
21
+ def queue
22
+ @queue
23
+ end
24
+
25
+ def length
26
+ queue.length
27
+ end
28
+
29
+ def working?
30
+ length > 0
31
+ end
32
+
33
+ def push(something)
34
+ self.queue = queue.push(something)
35
+ end
36
+
37
+ def unshift(something)
38
+ self.queue = queue.unshift(something)
39
+ end
40
+
41
+ def shift
42
+ queue.shift
43
+ end
44
+
45
+ def first
46
+ queue.first
47
+ end
48
+
49
+ alias :get :shift
50
+ alias :remove! :shift
51
+ alias :add :push
52
+ alias :amount :length
53
+ alias :size :length
54
+ alias :<< :push
55
+ alias :>> :unshift
56
+
57
+ def start!
58
+ unless running?
59
+ logger.info "Starting!!! #{name}..."
60
+
61
+ @t = Thread.new(name) do |my_name|
62
+ loop do
63
+ MerbQueue[my_name].next!
64
+ MerbQueue[my_name].working? ? sleep(0.25) : sleep(wait_seconds)
65
+ end
66
+ end
67
+ @t.priority = -9
68
+
69
+ @running = true
70
+ end
71
+ end#of start!
72
+
73
+ def start
74
+ unless running?
75
+ logger.info "Starting #{name}..."
76
+
77
+ @t = Thread.new(name) do |my_name|
78
+ loop do
79
+ MerbQueue[my_name].next
80
+ MerbQueue[my_name].working? ? sleep(0.25) : sleep(wait_seconds)
81
+ end
82
+ end
83
+ @t.priority = -9
84
+
85
+ @running = true
86
+ end
87
+ end#of start
88
+
89
+ def clear!
90
+ @queue = [] # TODO: this might should be a bit nicer?
91
+ end
92
+
93
+ def next
94
+ begin
95
+ self.next!
96
+ rescue MerbQueueError::QueueEmpty
97
+ rescue Exception => e
98
+ logger.error(e) # TODO: log this somewhere?
99
+ end
100
+ end#of next
101
+
102
+ def next!
103
+
104
+ current_work = self.get # pull an item off the top of the queue
105
+ max_tries = @max_attempts
106
+ raise MerbQueueError::QueueEmpty if current_work.nil?
107
+ raise MerbQueueError::WrongQueueDatatype unless current_work.is_a?(Hash)
108
+ current_work[:attempts] = current_work[:attempts] ? current_work[:attempts] + 1 : 1
109
+
110
+ begin
111
+ @work_to_be_done.call(current_work)
112
+ rescue Exception => e
113
+ if current_work[:attempts] >= max_tries
114
+ logger.error "#### This crap just doesn't work!"
115
+ logger.error current_work.to_yaml
116
+ # TODO: log this failure and all the errors somewhere?
117
+ else
118
+ current_work[:errors] = current_work[:errors] ? current_work[:errors] << e : current_work[:errors] = [e]
119
+ self << current_work # put it back so it can try again
120
+
121
+ logger.warn "There was an error, trying again."
122
+ logger.error e
123
+ end
124
+ end
125
+
126
+ end#of next!
127
+
128
+ end#of Queue class
129
+
130
+ end
@@ -0,0 +1,9 @@
1
+ module MerbQueue
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ # Time to add your specs!
4
+ # http://rspec.info/
5
+ describe MerbQueue do
6
+
7
+ describe "adding" do
8
+
9
+ before(:each) do
10
+ MerbQueue.delete(:test)
11
+ end
12
+
13
+ it "should let you add" do
14
+ MerbQueue.should respond_to(:add)
15
+ MerbQueue.add(:test) { |w| true }
16
+ MerbQueue[:test].should_not be_nil
17
+ end
18
+
19
+ it "should know how long the queue is" do
20
+ MerbQueue[:test].should be_nil # just to make sure the queue from before is now gone
21
+
22
+ MerbQueue::Queue.stubs(:next).returns(true)
23
+
24
+ MerbQueue.add(:test) { |w| true }
25
+ MerbQueue[:test].length.should == 0
26
+
27
+ MerbQueue[:test] << {}
28
+ MerbQueue[:test].length.should == 1
29
+ end
30
+
31
+ it "should report that it's not running" do
32
+ MerbQueue.add(:test) { |w| true }
33
+ MerbQueue[:test].should_not be_running
34
+ end
35
+ end
36
+
37
+ describe "registering" do
38
+
39
+ before(:each) do
40
+ MerbQueue.delete(:test)
41
+ end
42
+
43
+ it "should let you register" do
44
+ MerbQueue::Queue.stubs(:next).returns(true)
45
+
46
+ MerbQueue.should respond_to(:register)
47
+ MerbQueue.register(:test) { |w| true }
48
+ MerbQueue[:test].should_not be_nil
49
+ end
50
+
51
+ it "should start a queue that is registered" do
52
+ MerbQueue::Queue.expects(:start).returns(true)
53
+ MerbQueue.register(:test) { |w| true }
54
+ end
55
+
56
+ it "should know that it's running" do
57
+ MerbQueue::Queue.stubs(:next).returns(true)
58
+
59
+ MerbQueue.register(:test) { |w| true }
60
+ MerbQueue[:test].should be_running
61
+ end
62
+
63
+ end
64
+
65
+ describe "looping" do
66
+
67
+ before(:each) do
68
+ MerbQueue.delete(:test)
69
+ end
70
+
71
+ it "should be processing the queue every so often and in order" do
72
+ $counter = 1
73
+ MerbQueue.add(:test) { |w| $counter = w[:amount] }
74
+ MerbQueue[:test].wait_seconds = 0
75
+
76
+ MerbQueue[:test] << { :amount => 1 }
77
+ MerbQueue[:test] << { :amount => 2 }
78
+ MerbQueue[:test] << { :amount => 3 }
79
+ MerbQueue[:test] << { :amount => 4 }
80
+
81
+ MerbQueue[:test].start
82
+
83
+ sleep(1.25) # wait on the thread to process
84
+
85
+ MerbQueue[:test].should_not be_working
86
+ $counter.should == 4
87
+ end
88
+
89
+ it "should know how many items are left to go" do
90
+ MerbQueue.add(:test) { |w| true }
91
+ MerbQueue[:test] << {}
92
+ MerbQueue[:test] << {}
93
+ MerbQueue[:test].amount.should == 2
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,25 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $TESTING=true
10
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
11
+ require 'rubygems'
12
+ require 'mocha'
13
+ require "merb-core"
14
+ require 'merb_queue'
15
+
16
+ Merb.load_dependencies :environment => "test"
17
+
18
+ Spec::Runner.configure do |config|
19
+ # config.include(Merb::Test::ViewHelper)
20
+ config.include Merb::Test::RouteHelper
21
+ config.include Merb::Test::RequestHelper
22
+ config.include Merb::Test::ControllerHelper
23
+ end
24
+
25
+ Merb.load_dependencies(:environment => 'test')
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: myobie-merb_queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Herald
8
+ autorequire: merb_queue
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-25 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-core
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.3
23
+ version:
24
+ description: A persistent queue across multiple merb processes
25
+ email: nathan@myobie.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README.markdown
32
+ - LICENSE
33
+ - TODO
34
+ files:
35
+ - LICENSE
36
+ - README.markdown
37
+ - Rakefile
38
+ - TODO
39
+ - lib/merb_queue
40
+ - lib/merb_queue/base.rb
41
+ - lib/merb_queue/queue.rb
42
+ - lib/merb_queue/version.rb
43
+ - lib/merb_queue.rb
44
+ - spec/merb_queue_spec.rb
45
+ - spec/spec.opts
46
+ - spec/spec_helper.rb
47
+ has_rdoc: false
48
+ homepage: http://github.com/myobie/merb_queue
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.2.0
70
+ signing_key:
71
+ specification_version: 2
72
+ summary: A persistent queue across multiple merb processes
73
+ test_files: []
74
+