rabbit-wq 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ gemdev
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p392
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in brer_rabbit.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jason Harrelson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # RabbitWQ
2
+
3
+ A work queue built on RabbitMQ and Celluloid.
4
+
5
+ This is NOT production ready. Released only to reserve gem name.
6
+
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'rabbit-wq'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install rabbit-wq
21
+
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+
28
+ ## Contributing
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/rabbit-wq ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rabbit_wq/cli'
data/lib/rabbit-wq.rb ADDED
@@ -0,0 +1 @@
1
+ require "rabbit_wq"
data/lib/rabbit_wq.rb ADDED
@@ -0,0 +1,34 @@
1
+ require "rabbit_wq/version"
2
+
3
+ module RabbitWQ
4
+
5
+ APP_ID = "rabbit-wq"
6
+ APP_NAME = "Rabbit Work Queue"
7
+ COMPANY = "Look Forward Enterprises"
8
+ DELAY_QUEUE_PREFIX = "work-delay" # TODO: Make this configurable (from ENV, or file?)
9
+ DELAY_EXCHANGE_PREFIX = "work-delay" # TODO: Make this configurable (from ENV, or file?)
10
+ INT = "INT"
11
+ QUEUE = "work" # TODO: Make this configurable (from ENV, or file?)
12
+ VERSION_COPYRIGHT = "v#{VERSION} \u00A9#{Time.now.year} #{COMPANY}"
13
+ WORK_EXCHANGE = "work" # TODO: Make this configurable (from ENV, or file?)
14
+
15
+ autoload :Configuration, 'rabbit_wq/configuration'
16
+ autoload :Logging, 'rabbit_wq/logging'
17
+ autoload :MessageHandler, 'rabbit_wq/message_handler'
18
+ autoload :Server, 'rabbit_wq/server'
19
+ autoload :ServerLogging, 'rabbit_wq/server_logging'
20
+ autoload :Work, 'rabbit_wq/work'
21
+
22
+ def self.configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def self.configure
27
+ yield( configuration ) if block_given?
28
+ end
29
+
30
+ class << self
31
+ attr_accessor :logger
32
+ end
33
+
34
+ end
@@ -0,0 +1,107 @@
1
+ require 'rubygems'
2
+ require 'rabbit_wq'
3
+ require 'trollop'
4
+ require 'yell'
5
+
6
+ module RabbitWQ
7
+ module Cli
8
+
9
+ SUB_COMMANDS = %w(
10
+ restart
11
+ start
12
+ status
13
+ stop
14
+ )
15
+
16
+ def self.start( options )
17
+ if options[:interactive]
18
+ start_interactive options
19
+ else
20
+ start_daemon options
21
+ end
22
+ end
23
+
24
+ def self.start_interactive( options )
25
+ server = RabbitWQ::Server.new( options.merge( log: nil ) )
26
+ server.start
27
+ end
28
+
29
+ def self.start_daemon( options )
30
+ server = RabbitWQ::ServerDaemon.new( options )
31
+ server.start
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ DEFAULT_LOG_PATH = "/var/log/rabbit-wq/#{RabbitWQ::APP_ID}.log"
38
+ DEFAULT_PID_PATH = "/var/run/rabbit-wq/#{RabbitWQ::APP_ID}.pid"
39
+
40
+ global_opts = Trollop::options do
41
+ version RabbitWQ::VERSION_COPYRIGHT
42
+ banner <<-EOS
43
+ #{RabbitWQ::APP_NAME} #{RabbitWQ::VERSION_COPYRIGHT}
44
+
45
+ Usage:
46
+ #{RabbitWQ::APP_ID} [command] [options]
47
+
48
+ commands:
49
+ #{RabbitWQ::Cli::SUB_COMMANDS.map { |cmd| " #{cmd}" }.join( "\n" )}
50
+
51
+ (For help with a command: #{RabbitWQ::APP_ID} [command] -h)
52
+
53
+ options:
54
+ EOS
55
+ stop_on RabbitWQ::Cli::SUB_COMMANDS
56
+ end
57
+
58
+ # Get the sub-command and its options
59
+ #
60
+ cmd = ARGV.shift || ''
61
+ cmd_opts = case( cmd )
62
+ #when "restart"
63
+ #Trollop::options do
64
+ #opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
65
+ #end
66
+ when "start"
67
+ Trollop::options do
68
+ opt :interactive, "Execute the server in interactive mode", :short => '-i'
69
+ opt :log_level, "The log level", :type => String, :default => 'info'
70
+ opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
71
+ opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
72
+ end
73
+ #when "status"
74
+ #Trollop::options do
75
+ #opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
76
+ #end
77
+ #when "stop"
78
+ #Trollop::options do
79
+ #opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
80
+ #end
81
+ else
82
+ Trollop::die "unknown command #{cmd.inspect}"
83
+ end
84
+
85
+ if cmd == 'start'
86
+ unless cmd_opts[:interactive]
87
+ Trollop::die( :log, "is required when running as daemon" ) unless cmd_opts[:log]
88
+ Trollop::die( :pid, "is required when running as daemon" ) unless cmd_opts[:pid]
89
+ end
90
+ end
91
+
92
+ if %w(restart status stop).include?( cmd )
93
+ Trollop::die( :pid, "is required" ) unless cmd_opts[:pid]
94
+ end
95
+
96
+ # Execute the command
97
+ #
98
+ case cmd
99
+ when "restart"
100
+ RabbitWQ::ServerDaemon.new( cmd_opts ).restart
101
+ when "start"
102
+ RabbitWQ::Cli.start cmd_opts
103
+ when "status"
104
+ RabbitWQ::ServerDaemon.new( cmd_opts ).status
105
+ when "stop"
106
+ RabbitWQ::ServerDaemon.new( cmd_opts ).stop
107
+ end
@@ -0,0 +1,13 @@
1
+ module RabbitWQ
2
+ class Configuration
3
+
4
+ #def authentication_token
5
+ #@authentication_token
6
+ #end
7
+
8
+ #def authentication_token=( authentication_token )
9
+ #@authentication_token = authentication_token
10
+ #end
11
+
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module RabbitWQ
2
+ module Logging
3
+
4
+ %w(
5
+ debug
6
+ error
7
+ fatal
8
+ info
9
+ warn
10
+ ).each do |level|
11
+
12
+ define_method level do |*messages|
13
+ messages.each do |message|
14
+ RabbitWQ.logger.send level, message
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ require 'celluloid/autostart'
2
+
3
+ module RabbitWQ
4
+ class MessageHandler
5
+
6
+ include Celluloid
7
+ include Logging
8
+
9
+ REQUEUE = true
10
+
11
+ def call( options )
12
+ channel = options[:channel]
13
+ delivery_info = options[:delivery_info]
14
+ metadata = options[:metadata]
15
+ payload = options[:payload]
16
+
17
+ info "PAYLOAD ARRIVED #{payload}"
18
+ channel.ack delivery_info.delivery_tag
19
+ end
20
+
21
+ protected
22
+
23
+ def requeue( channel, delivery_info, e=nil )
24
+ info ANSI.yellow { 'REQUEUE ' + e.message }
25
+ channel.reject delivery_info.delivery_tag, REQUEUE
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ require 'bunny'
2
+
3
+ module RabbitWQ
4
+ class Server
5
+
6
+ include ServerLogging
7
+ include Logging
8
+
9
+ attr_reader :message_consumer,
10
+ :options,
11
+ :work_exchange
12
+
13
+ def initialize( options )
14
+ @options = options
15
+ options[:pool_size] ||= 2 # TODO move to external configuration
16
+
17
+ configure_server
18
+ end
19
+
20
+ def start
21
+ log_startup
22
+ run
23
+
24
+ trap( INT ) { finalize; exit }
25
+ sleep
26
+ end
27
+
28
+ protected
29
+
30
+ def finalize
31
+ info "SHUTTING DOWN"
32
+ message_consumer.cancel
33
+ mq.close
34
+ end
35
+
36
+ def mq
37
+ @mq ||= ::Bunny.new.tap do |bunny|
38
+ bunny.start
39
+ end
40
+ end
41
+
42
+ def channel
43
+ @channel ||= mq.create_channel
44
+ end
45
+
46
+ def work_exchange
47
+ @work_exchange ||= channel.direct( WORK_EXCHANGE, durable: true )
48
+ end
49
+
50
+ def queue
51
+ @queue ||= channel.queue( QUEUE,
52
+ durable: true ).
53
+ bind( work_exchange )
54
+ end
55
+
56
+ def pool
57
+ @pool ||= MessageHandler.pool( size: options[:pool_size] )
58
+ end
59
+
60
+ def run
61
+ @message_consumer = queue.subscribe( manual_ack: true ) do |delivery_info, metadata, payload|
62
+ debug "LISTENER RECEIVED #{payload}"
63
+
64
+ pool.async.call( payload: payload,
65
+ delivery_info: delivery_info,
66
+ metadata: metadata,
67
+ channel: channel )
68
+ end
69
+ end
70
+
71
+ def configure_server
72
+ initialize_loggers
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,53 @@
1
+ require 'yell'
2
+
3
+ # Provides logging services for the base server.
4
+ #
5
+ module RabbitWQ
6
+ module ServerLogging
7
+
8
+ protected
9
+
10
+ def initialize_loggers
11
+ if options[:interactive] || options[:log].nil? || options[:log].empty?
12
+ RabbitWQ.logger = Yell.new do |l|
13
+ l.level = log_level
14
+ l.adapter $stdout, :level => [:debug, :info, :warn]
15
+ l.adapter $stderr, :level => [:error, :fatal]
16
+ end
17
+ else
18
+ RabbitWQ.logger = Yell.new do |l|
19
+ l.level = log_level
20
+ l.adapter :file, options[:log]
21
+ end
22
+
23
+ Celluloid.logger = Yell.new do |l|
24
+ l.level = :info
25
+ l.adapter :file, File.join( File.dirname( options[:log] ), "#{APP_ID}-celluloid.log" )
26
+ end
27
+ end
28
+ end
29
+
30
+ def log_startup
31
+ start_banner( options ).each do |line|
32
+ RabbitWQ.logger.info line
33
+ end
34
+ end
35
+
36
+ def start_banner( options )
37
+ [
38
+ "",
39
+ "***",
40
+ "* #{RabbitWQ::APP_NAME} started",
41
+ "*",
42
+ "* #{VERSION_COPYRIGHT}",
43
+ "***",
44
+ "",
45
+ ]
46
+ end
47
+
48
+ def log_level
49
+ options.fetch( :log_level, :info ).to_sym
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module RabbitWQ
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ require 'bunny'
2
+
3
+ module RabbitWQ
4
+ module Work
5
+
6
+ def self.enqueue( worker, options={} )
7
+ options[:delay] = nil if options[:delay] && options[:delay] < 5000
8
+
9
+ mq = ::Bunny.new.tap { |bunny| bunny.start }
10
+ channel = mq.create_channel
11
+
12
+ if options[:delay]
13
+ delay_x = channel.direct( "#{DELAY_EXCHANGE_PREFIX}-#{options[:delay]}ms", durable: true )
14
+ work_x = channel.direct( WORK_EXCHANGE, durable: true )
15
+ queue = channel.queue( "#{DELAY_QUEUE_PREFIX}-#{options[:delay]}ms",
16
+ durable: true,
17
+ arguments: { "x-dead-letter-exchange" => work_x.name,
18
+ "x-message-ttl" => options[:delay] } ).
19
+ bind( delay_x )
20
+
21
+ delay_x.publish( 'hello', durable: true )
22
+ return
23
+ end
24
+
25
+ work_q = channel.queue( QUEUE, durable: true )
26
+ work_q.publish( 'hello', durable: true )
27
+ end
28
+
29
+ end
30
+ end
data/rabbit-wq.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rabbit_wq/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rabbit-wq"
8
+ spec.version = RabbitWQ::VERSION
9
+ spec.authors = ["C. Jason Harrelson"]
10
+ spec.email = ["jason@lookforwardenterprises.com"]
11
+ spec.description = %q{A work queue built on RabbitMQ and Celluloid. See README for more details.}
12
+ spec.summary = %q{A work queue built on RabbitMQ and Celluloid.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = ['rabbit-wq'] #spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "bunny", "~> 1"
25
+ spec.add_dependency "celluloid", "~> 0"
26
+ spec.add_dependency "trollop", "~> 2"
27
+ spec.add_dependency "yell", "~> 1"
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rabbit-wq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - C. Jason Harrelson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bunny
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ - !ruby/object:Gem::Dependency
63
+ name: celluloid
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: trollop
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '2'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '2'
94
+ - !ruby/object:Gem::Dependency
95
+ name: yell
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '1'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '1'
110
+ description: A work queue built on RabbitMQ and Celluloid. See README for more details.
111
+ email:
112
+ - jason@lookforwardenterprises.com
113
+ executables:
114
+ - rabbit-wq
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .ruby-gemset
120
+ - .ruby-version
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/rabbit-wq
126
+ - lib/rabbit-wq.rb
127
+ - lib/rabbit_wq.rb
128
+ - lib/rabbit_wq/cli.rb
129
+ - lib/rabbit_wq/configuration.rb
130
+ - lib/rabbit_wq/logging.rb
131
+ - lib/rabbit_wq/message_handler.rb
132
+ - lib/rabbit_wq/server.rb
133
+ - lib/rabbit_wq/server_logging.rb
134
+ - lib/rabbit_wq/version.rb
135
+ - lib/rabbit_wq/work.rb
136
+ - rabbit-wq.gemspec
137
+ homepage: ''
138
+ licenses:
139
+ - MIT
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ segments:
151
+ - 0
152
+ hash: -1285656029023150188
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ segments:
160
+ - 0
161
+ hash: -1285656029023150188
162
+ requirements: []
163
+ rubyforge_project:
164
+ rubygems_version: 1.8.25
165
+ signing_key:
166
+ specification_version: 3
167
+ summary: A work queue built on RabbitMQ and Celluloid.
168
+ test_files: []