adamwiggins-minion 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+
2
+ = Minion: super simple job queue over amqp
3
+
4
+ Minion makes processing jobs over AMQP simple and easy.
5
+
6
+ == Setup
7
+
8
+ Minion pulls the AMQP credentials out the environment via AMQP_URI.
9
+
10
+ $ export AMQP_URI="amqp://johndoe:abc123@localhost/my_vhost"
11
+
12
+ If no URI is supplied, Minion defaults to "amqp://guest:guest@localhost/" which
13
+ is the default credentials for Rabbitmq running locally.
14
+
15
+ == Principles
16
+
17
+ Minion treats your jobs with respect. The queues are durable and not
18
+ autodelete. When popping jobs off the queue, they will not receive an ack
19
+ until the job is done. You can rest assured that once queued, the job will not
20
+ be lost.
21
+
22
+ Sends are done synchronously and receives are done asynchronously. This allows
23
+ you to Minion.enqueue() from the console, or in a mongrel and you don't need to
24
+ worry about eventmachine. It also means that when enqueue returns, the AMQP
25
+ server has received your message. Daemons set to receive messages however use
26
+ eventmachine.
27
+
28
+ Message processing is done one at a time (prefetch 1). If you want tasks done
29
+ in parallel, run two minions.
30
+
31
+ == Push a job onto the queue
32
+
33
+ Its easy to push a job onto the queue.
34
+
35
+ Minion.enqueue("make.sandwich", { "for" => "me", "with" => "bread" })
36
+
37
+ Minion expects a queue name (and will create it if needed). The second argument
38
+ needs to be a hash.
39
+
40
+ == Processing a job
41
+
42
+ require 'minion'
43
+
44
+ include Minion
45
+
46
+ job "make.sandwich" do |args|
47
+ Sandwich.make(args["for"],args["with"])
48
+ end
49
+
50
+ == Chaining multiple steps
51
+
52
+ If you have a task that requires more than one step just pass an array of
53
+ queues when you enqueue.
54
+
55
+ Minion.enqueue([ "make.sandwich", "eat.sandwich" ], "for" => "me")
56
+
57
+ job "make.sandwich" do
58
+ ## this return value is merged with for => me and sent to the next queue
59
+ { "type" => "ham on rye" }
60
+ end
61
+
62
+ job "eat.sandwich" do |args|
63
+ puts "I have #{args["type"]} sandwich for #{args["me"]}"
64
+ end
65
+
66
+ == Error handling
67
+
68
+ When an error is thrown in a job handler, the job is requeued to be done later
69
+ and the minion process exits. If you define an error handler, however, the
70
+ error handler is run and the job is removed from the queue.
71
+
72
+ on_error do |e|
73
+ puts "got an error! #{e}"
74
+ end
75
+
76
+ == Logging
77
+
78
+ Minion logs to stdout via "puts". You can specify a custom logger like this:
79
+
80
+ logger do |msg|
81
+ puts msg
82
+ end
83
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'minion'
5
+
6
+ include Minion
7
+
8
+ on_error do |e|
9
+ puts "got an error!"
10
+ end
11
+
12
+ logger do |msg|
13
+ puts "--> #{msg}"
14
+ end
15
+
16
+ job "math.incr" do |args|
17
+ { "number" => (1 + args["number"].to_i) }
18
+ end
19
+
20
+ job "math.double" do |args|
21
+ { "number" => (2 * args["number"].to_i) }
22
+ end
23
+
24
+ job "math.square" do |args|
25
+ { "number" => (args["number"].to_i * args["number"].to_i) }
26
+ end
27
+
28
+ job "math.print" do |args|
29
+ puts "NUMBER -----> #{args["number"]}"
30
+ end
31
+
32
+ enqueue([ "math.incr", "math.double", "math.square", "math.incr", "math.double", "math.print" ], { :number => 3 })
33
+
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'minion'
5
+
6
+ include Minion
7
+
8
+ job "add.bread" do |args|
9
+ { "bread" => "sourdough" }
10
+ end
11
+
12
+ job "add.meat" do |args|
13
+ { "meat" => "turkey" }
14
+ end
15
+
16
+ job "add.condiments" do |args|
17
+ { "condiments" => "mayo" }
18
+ end
19
+
20
+ job "eat.sandwich" do |args|
21
+ puts "YUM! A #{args['meat']} on #{args['bread']} sandwich with #{args['condiments']}"
22
+ end
23
+
24
+ enqueue(["add.bread", "add.meat", "add.condiments", "eat.sandwich" ])
25
+
@@ -0,0 +1,114 @@
1
+ require 'uri'
2
+ require 'json'
3
+ require 'mq'
4
+ require 'bunny'
5
+
6
+ module Minion
7
+ extend self
8
+
9
+ def enqueue(jobs, data = {})
10
+ ## jobs can be one or more jobs
11
+ if jobs.respond_to? :shift
12
+ queue = jobs.shift
13
+ data["next_job"] = jobs unless jobs.empty?
14
+ else
15
+ queue = jobs
16
+ end
17
+
18
+ log "send: #{queue}:#{data.to_json}"
19
+ bunny.queue(queue, :durable => true, :auto_delete => false).publish(data.to_json)
20
+ end
21
+
22
+ def on_error(&blk)
23
+ @@error_handler = blk
24
+ end
25
+
26
+ def logger(&blk)
27
+ @@logger = blk
28
+ end
29
+
30
+ def job(queue, &blk)
31
+ handler do
32
+ MQ.queue(queue).subscribe(:ack => true) do |h,m|
33
+ return if AMQP.closing?
34
+ begin
35
+ log "recv: #{queue}:#{m}"
36
+
37
+ args = JSON.load(m)
38
+
39
+ result = yield(args)
40
+
41
+ next_job(args, result)
42
+ rescue Object => e
43
+ raise unless error_handler
44
+ error_handler.call(e)
45
+ end
46
+ h.ack
47
+ end
48
+ end
49
+ end
50
+
51
+ def run
52
+ log "Starting minion"
53
+
54
+ Signal.trap('INT') { AMQP.stop{ EM.stop } }
55
+ Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
56
+
57
+ EM.run do
58
+ AMQP.start(amqp_config) do
59
+ MQ.prefetch(1)
60
+ @@handlers.each { |h| h.call }
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def amqp_url
68
+ ENV["AMQP_URL"] || "amqp://guest:guest@localhost/"
69
+ end
70
+
71
+ def amqp_config
72
+ uri = URI.parse(amqp_url)
73
+ {
74
+ :vhost => uri.path,
75
+ :host => uri.host,
76
+ :user => uri.user,
77
+ :port => (uri.port || 5672),
78
+ :pass => uri.password
79
+ }
80
+ rescue
81
+ raise "invalid AMQP_URL: #{uri.inspect} (#{e})"
82
+ end
83
+
84
+ def new_bunny
85
+ b = Bunny.new(amqp_config)
86
+ b.start
87
+ b
88
+ end
89
+
90
+ def bunny
91
+ @@bunny ||= new_bunny
92
+ end
93
+
94
+ def log(msg)
95
+ @@logger ||= proc { |m| puts "#{Time.now} :minion: #{m}" }
96
+ @@logger.call(msg)
97
+ end
98
+
99
+ def handler(&blk)
100
+ @@handlers ||= []
101
+ at_exit { Minion.run } if @@handlers.size == 0
102
+ @@handlers << blk
103
+ end
104
+
105
+ def next_job(args, response)
106
+ queue = args.delete("next_job")
107
+ enqueue(queue,args.merge(response)) if queue
108
+ end
109
+
110
+ def error_handler
111
+ @@error_handler ||= nil
112
+ end
113
+ end
114
+
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: adamwiggins-minion
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Orion Henry
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-19 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: tmm1-amqp
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.6.4
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.7
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: bunny
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.2
44
+ version:
45
+ description: Super simple job queue over AMQP
46
+ email: orion@heroku.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - README.rdoc
53
+ files:
54
+ - README.rdoc
55
+ - VERSION
56
+ - examples/math.rb
57
+ - examples/sandwich.rb
58
+ - lib/minion.rb
59
+ has_rdoc: true
60
+ homepage: http://github.com/orionz/minion
61
+ licenses:
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project: minion
82
+ rubygems_version: 1.3.5
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: Super simple job queue over AMQP
86
+ test_files:
87
+ - examples/math.rb
88
+ - examples/sandwich.rb