bluth 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -1,5 +1,18 @@
1
1
  BLUTH, CHANGES
2
2
 
3
+ #### 0.6.0 (2010-12-30) ###############################
4
+
5
+ * CHANGE: Now depends on Familia 0.6
6
+ * CHANGE: Worker process name now starts with 'bluth'
7
+ * CHANGE: Bluth.pop is now correctly named Bluth.shift (b/c it's returning
8
+ the first value in the lists)
9
+ * ADDED: Bluth::Handler
10
+
11
+
12
+ #### 0.5.3 (2010-12-17) ###############################
13
+
14
+ * CHANGE: requires Familia 0.5.3
15
+
3
16
  #### 0.5.2 (2010-12-10) ###############################
4
17
 
5
18
  Initial public release
data/Rakefile CHANGED
@@ -25,8 +25,9 @@ begin
25
25
  gem.email = "delano@solutious.com"
26
26
  gem.homepage = "http://github.com/delano/bluth"
27
27
  gem.authors = ["Delano Mandelbaum"]
28
- gem.add_dependency("familia", "= 0.5.3")
28
+ gem.add_dependency("familia", "= 0.6.3")
29
29
  gem.add_dependency('sysinfo', '>= 0.7.3')
30
+ gem.add_dependency('annoy')
30
31
 
31
32
  #gem.add_development_dependency("rspec", ">= 1.2.9")
32
33
  #gem.add_development_dependency("mocha", ">= 0.9.8")
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :MAJOR: 0
3
- :MINOR: 5
4
- :PATCH: 3
3
+ :MINOR: 6
4
+ :PATCH: 0
data/bin/bluth ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # = Bluth: the queuing system.
4
+ #
5
+ #
6
+ # Usage:
7
+ #
8
+ # $ bluth -h
9
+ # $ bluth -Ipath/2/inc -ryourlib start
10
+ # $ bluth -Ipath/2/inc -ryourlib stop
11
+ #
12
+ #--
13
+
14
+ # Put our local lib in first place
15
+ BASE_PATH = File.expand_path File.join(File.dirname(__FILE__), '..')
16
+ $:.unshift File.join(BASE_PATH, 'lib')
17
+
18
+ require 'bluth'
19
+ require 'bluth/cli'
20
+
21
+ autoload :Rye, 'rye'
22
+ autoload :Annoy, 'annoy'
23
+
24
+ # Command-line interface for bin/bluth
25
+ class Bluth::CLI::Definition
26
+ extend Drydock
27
+
28
+ debug :on
29
+
30
+ global :Y, :auto, "Auto confirm"
31
+ global :d, :database, Integer, "Redis database"
32
+ global :e, :environment, String
33
+ global :d, :daemon, "Start as a daemon"
34
+ global :D, :debug do
35
+ Familia.debug = true
36
+ end
37
+ global :U, :uri, String, "Redis connection URI" do |v|
38
+ uri = URI.parse v
39
+ Bluth.uri = uri
40
+ end
41
+ global :v, :verbose, "Increase output" do
42
+ @verbose ||= 0
43
+ @verbose += 1
44
+ end
45
+ global :I, String, "Add a load path" do |v|
46
+ $LOAD_PATH << v
47
+ end
48
+ global :r, String, "Require a library" do |v|
49
+ $LOAD_PATH << 'lib' if File.exists? 'lib'
50
+ begin
51
+ require v
52
+ rescue LoadError => ex
53
+ puts ex.message
54
+ exit
55
+ end
56
+ end
57
+ global :V, :version, "Display version" do
58
+ puts "Version: #{Bluth::VERSION.to_s}"
59
+ exit 0
60
+ end
61
+
62
+ before do |obj|
63
+ obj.global.environment ||= 'dev'
64
+ end
65
+
66
+ #TODO: command :enqueue
67
+
68
+ command :start_worker => Bluth::CLI
69
+ command :start_scheduler => Bluth::CLI
70
+
71
+ option :f, :force
72
+ command :stop_workers => Bluth::CLI
73
+ option :f, :force
74
+ command :stop_worker => Bluth::CLI
75
+ option :f, :force
76
+ command :stop_scheduler => Bluth::CLI
77
+
78
+ command :workers => Bluth::CLI
79
+ command :schedulers => Bluth::CLI
80
+
81
+ #command :flush_workers => Bluth::CLI
82
+ end
83
+
84
+ begin
85
+ Drydock.run!(ARGV, STDIN) if Drydock.run? && !Drydock.has_run?
86
+ rescue Drydock::ArgError, Drydock::OptError => ex
87
+ STDERR.puts ex.message
88
+ STDERR.puts ex.usage
89
+ rescue Drydock::InvalidArgument => ex
90
+ STDERR.puts ex.message
91
+ rescue Drydock::UnknownCommand => ex
92
+ STDERR.puts "Unknown command: %s" % ex.name
93
+ rescue Interrupt
94
+ puts $/, "Exiting..."
95
+ exit 1
96
+ rescue => ex
97
+ STDERR.puts "ERROR (#{ex.class.to_s}): #{ex.message}"
98
+ STDERR.puts ex.backtrace #if Familia.debug
99
+ end
data/bluth.gemspec CHANGED
@@ -5,13 +5,15 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bluth}
8
- s.version = "0.5.3"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Delano Mandelbaum"]
12
- s.date = %q{2010-12-17}
12
+ s.date = %q{2010-12-30}
13
+ s.default_executable = %q{bluth}
13
14
  s.description = %q{A Redis queuing system built on top of Familia}
14
15
  s.email = %q{delano@solutious.com}
16
+ s.executables = ["bluth"]
15
17
  s.extra_rdoc_files = [
16
18
  "LICENSE.txt",
17
19
  "README.rdoc"
@@ -22,11 +24,19 @@ Gem::Specification.new do |s|
22
24
  "README.rdoc",
23
25
  "Rakefile",
24
26
  "VERSION.yml",
27
+ "bin/bluth",
25
28
  "bluth.gemspec",
26
29
  "lib/bluth.rb",
30
+ "lib/bluth/cli.rb",
27
31
  "lib/bluth/gob.rb",
32
+ "lib/bluth/test_helpers.rb",
28
33
  "lib/bluth/worker.rb",
29
- "lib/daemonizing.rb"
34
+ "lib/daemonizing.rb",
35
+ "try/15_queue_try.rb",
36
+ "try/16_worker_try.rb",
37
+ "try/17_gob_try.rb",
38
+ "try/18_handler_try.rb",
39
+ "try/19_bluth_try.rb"
30
40
  ]
31
41
  s.homepage = %q{http://github.com/delano/bluth}
32
42
  s.rdoc_options = ["--charset=UTF-8"]
@@ -40,15 +50,18 @@ Gem::Specification.new do |s|
40
50
  s.specification_version = 3
41
51
 
42
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
- s.add_runtime_dependency(%q<familia>, ["= 0.5.3"])
53
+ s.add_runtime_dependency(%q<familia>, ["= 0.6.3"])
44
54
  s.add_runtime_dependency(%q<sysinfo>, [">= 0.7.3"])
55
+ s.add_runtime_dependency(%q<annoy>, [">= 0"])
45
56
  else
46
- s.add_dependency(%q<familia>, ["= 0.5.3"])
57
+ s.add_dependency(%q<familia>, ["= 0.6.3"])
47
58
  s.add_dependency(%q<sysinfo>, [">= 0.7.3"])
59
+ s.add_dependency(%q<annoy>, [">= 0"])
48
60
  end
49
61
  else
50
- s.add_dependency(%q<familia>, ["= 0.5.3"])
62
+ s.add_dependency(%q<familia>, ["= 0.6.3"])
51
63
  s.add_dependency(%q<sysinfo>, [">= 0.7.3"])
64
+ s.add_dependency(%q<annoy>, [">= 0"])
52
65
  end
53
66
  end
54
67
 
data/lib/bluth/cli.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'drydock'
2
+
3
+ module Bluth
4
+ class CLI < Drydock::Command
5
+
6
+
7
+ def start_workers
8
+ start_worker
9
+ end
10
+
11
+ def start_scheduler
12
+ start_worker Bluth.scheduler
13
+ end
14
+
15
+ def stop_scheduler
16
+ stop_workers Bluth.scheduler
17
+ end
18
+
19
+ def schedulers
20
+ workers Bluth.scheduler
21
+ end
22
+
23
+ #def flush_workers
24
+ # if @global.auto || Annoy.are_you_sure?
25
+ # Bluth::Worker.prefix
26
+ # end
27
+ #end
28
+
29
+ def start_worker worker_class=Bluth::Worker
30
+ if @global.daemon
31
+ worker = worker_class.new
32
+ Familia.info "Created: #{worker.rediskey}"
33
+ worker.daemonize
34
+ worker.run
35
+ else
36
+ Bluth.poptimeout = 3.seconds
37
+ worker_class.run
38
+ end
39
+ end
40
+
41
+ def stop_workers worker_class=Bluth::Worker
42
+ worker_class.instances.each do |worker|
43
+ kill_worker worker, worker_class
44
+ end
45
+ end
46
+
47
+ def stop_worker wid=nil,worker_class=Bluth::Worker
48
+ wids = wid ? [wid] : @argv
49
+ wids.each do |wid|
50
+ worker = worker_class.from_redis wid
51
+ kill_worker worker, worker_class
52
+ end
53
+ end
54
+
55
+ def workers worker_class=Bluth::Worker
56
+ Familia.info worker_class.all.collect &:key
57
+ end
58
+
59
+ private
60
+
61
+ def kill_worker worker, worker_class=Bluth::Worker
62
+ if worker.nil?
63
+ Familia.info "No such worker"
64
+ exit 1
65
+ else
66
+ Familia.info "Killing #{worker.rediskey}"
67
+ worker.kill @global.auto
68
+ end
69
+ end
70
+
71
+ end
72
+ end
data/lib/bluth/gob.rb CHANGED
@@ -1,180 +1 @@
1
1
 
2
-
3
- module Bluth
4
-
5
- class Gob < Storable
6
- MAX_ATTEMPTS = 3.freeze unless defined?(Gob::MAX_ATTEMPTS)
7
- include Familia
8
- prefix :gob
9
- ttl 1.hour
10
- field :id => Gibbler::Digest
11
- field :kind => String
12
- field :data => Hash
13
- field :messages => Array
14
- field :attempts => Integer
15
- field :create_time => Float
16
- field :stime => Float
17
- field :etime => Float
18
- field :current_queue => String
19
- field :thread_id => Integer
20
- field :cpu => Array
21
- field :wid => Gibbler::Digest
22
-
23
- def self.inherited(obj)
24
- obj.extend Bluth::Gob::ClassMethods
25
- obj.prefix [:job, obj.to_s.split('::').last.downcase].join(':')
26
- Bluth.handlers << obj
27
- end
28
-
29
- module ClassMethods
30
- def clear
31
- keys.each do |key|
32
- Gob.redis.del key
33
- end
34
- end
35
- def enqueue(data={},q=nil)
36
- q ||= self.queue
37
- job = Gob.create generate_id(data), self, data
38
- job.current_queue = q
39
- Familia.ld "ENQUEUING: #{self} #{job.id.short} to #{q}"
40
- Bluth::Queue.redis.lpush q.key, job.id
41
- job.create_time = Time.now.utc.to_f
42
- job.attempts = 0
43
- job
44
- end
45
- def queue(name=nil)
46
- @queue = name if name
47
- @queue || Bluth::High
48
- end
49
- def generate_id(*args)
50
- a = [self, Process.pid, Bluth.sysinfo.hostname, Time.now.to_f, *args]
51
- a.gibbler
52
- end
53
- def all
54
- Bluth::Gob.all.select do |job|
55
- job.kind == self
56
- end
57
- end
58
- def size
59
- all.size
60
- end
61
- def lock_key
62
- Familia.key(prefix, :lock)
63
- end
64
- def lock!
65
- raise Bluth::Buster, "#{self} is already locked!" if locked?
66
- Familia.info "Locking #{self}"
67
- ret = Bluth::Gob.redis.set lock_key, 1
68
- Bluth.locks << lock_key
69
- ret == 'OK'
70
- end
71
- def unlock!
72
- Familia.info "Unlocking #{self}"
73
- ret = Bluth::Gob.redis.del lock_key
74
- Bluth.locks.delete lock_key
75
- ret
76
- end
77
- def locked?
78
- Bluth::Gob.redis.exists lock_key
79
- end
80
- def prepare
81
- end
82
-
83
- [:success, :failure, :running].each do |w|
84
- define_method "#{w}_key" do # success_key
85
- Familia.key(self.prefix, w)
86
- end
87
- define_method "#{w}!" do |*args| # success!(1)
88
- by = args.first || 1
89
- Bluth::Gob.redis.incrby send("#{w}_key"), by
90
- end
91
- define_method "#{w}" do # success
92
- Bluth::Gob.redis.get(send("#{w}_key")).to_i
93
- end
94
- end
95
- end
96
-
97
- def id
98
- @id = Gibbler::Digest.new(@id) if String === @id
99
- end
100
- def clear!
101
- @attempts = 0
102
- @messages = []
103
- save
104
- end
105
- def preprocess
106
- @attempts ||= 0
107
- @messages ||= []
108
- @create_time ||= Time.now.utc.to_f
109
- end
110
- def attempt?
111
- attempts < MAX_ATTEMPTS
112
- end
113
- def attempt!
114
- @attempts = attempts + 1
115
- end
116
- def current_queue
117
- @current_queue
118
- end
119
- def kind
120
- @kind = eval "::#{@kind}" rescue @kind if @kind.is_a?(String)
121
- @kind
122
- end
123
- def kind=(v)
124
- @kind = v
125
- end
126
- def perform
127
- @attempts += 1
128
- Familia.ld "PERFORM: #{self.to_hash.inspect}"
129
- @stime = Time.now.utc.to_f
130
- save # update the time
131
- self.kind.prepare if self.class.respond_to?(:prepare)
132
- self.kind.perform @data
133
- @etime = Time.now.utc.to_f
134
- save # update the time
135
- end
136
- def delayed?
137
- start = @stime || 0
138
- start > Time.now.utc.to_f
139
- end
140
- def retry!(msg=nil)
141
- move! Bluth::High, msg
142
- end
143
- def failure!(msg=nil)
144
- @etime = Time.now.utc.to_i
145
- self.kind.failure!
146
- move! Bluth::Failed, msg
147
- end
148
- def success!(msg=nil)
149
- @etime = Time.now.utc.to_i
150
- self.kind.success!
151
- move! Bluth::Successful, msg
152
- end
153
- def duration
154
- return 0 if @stime.nil?
155
- et = @etime || Time.now.utc.to_i
156
- et - @stime
157
- end
158
- def dequeue!
159
- Familia.ld "Deleting #{self.id} from #{current_queue.key}"
160
- Bluth::Queue.redis.lrem current_queue.key, 0, self.id
161
- end
162
- private
163
- def move!(to, msg=nil)
164
- @thread_id = $$
165
- if to.to_s == current_queue.to_s
166
- raise Bluth::Buster, "Cannot move job to the queue it's in: #{to}"
167
- end
168
- Familia.ld "Moving #{self.id.short} from #{current_queue.key} to #{to.key}"
169
- @messages << msg unless msg.nil? || msg.empty?
170
- # We push first to make sure we never lose a Gob ID. Instead
171
- # there's the small chance of a job ID being in two queues.
172
- Bluth::Queue.redis.lpush to.key, @id
173
- dequeue!
174
- save # update messages
175
- @current_queue = to
176
- end
177
- end
178
-
179
- end
180
-
@@ -0,0 +1,33 @@
1
+
2
+
3
+ module ExampleHandler
4
+ extend Bluth::Handler
5
+ queue :critical
6
+
7
+ # :hostid => String
8
+ # :force => Boolean (update all monitors)
9
+ def self.enqueue(opts={})
10
+ super opts, opts.delete(:queue)
11
+ end
12
+
13
+ def self.perform(data={})
14
+ begin
15
+
16
+ rescue => ex
17
+
18
+ end
19
+ end
20
+ end
21
+
22
+ class ExampleWorker < Bluth::Worker
23
+
24
+ end
25
+
26
+
27
+ Bluth::Worker.onstart do
28
+ puts "onstart called"
29
+ end
30
+
31
+ Bluth::Worker.onexit do
32
+ puts "onexit called"
33
+ end