romq 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +10 -0
- data/README.md +32 -0
- data/examples/client.rb +18 -0
- data/lib/romq.rb +5 -0
- data/lib/romq/config.rb +30 -0
- data/lib/romq/connection.rb +75 -0
- data/lib/romq/helpers.rb +44 -0
- data/lib/romq/version.rb +3 -0
- metadata +69 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# RoMQ
|
2
|
+
|
3
|
+
Stands for **Robust MQ** and makes your RabbitMQ clients handle the most
|
4
|
+
common exceptions gracefully. It's cluster-aware, so if you define a
|
5
|
+
list of rabbitmq hosts, it will keep re-trying to
|
6
|
+
connect by picking hosts at random.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'romq'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install romq
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
See the examples directory.
|
25
|
+
|
26
|
+
## Contributing
|
27
|
+
|
28
|
+
1. Fork it
|
29
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
30
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
31
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
32
|
+
5. Create new Pull Request
|
data/examples/client.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ap'
|
4
|
+
require_relative '../lib/romq'
|
5
|
+
|
6
|
+
RoMQ::Connection.new do |channel|
|
7
|
+
exchange = channel.direct("romq")
|
8
|
+
|
9
|
+
EM.add_periodic_timer(2) do
|
10
|
+
exchange.publish("Time is: #{Time.now}")
|
11
|
+
end
|
12
|
+
|
13
|
+
channel.queue("client.rb", exclusive: true).
|
14
|
+
bind(exchange).
|
15
|
+
subscribe do |metadata, payload|
|
16
|
+
ap payload
|
17
|
+
end
|
18
|
+
end
|
data/lib/romq.rb
ADDED
data/lib/romq/config.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module RoMQ
|
2
|
+
module Config
|
3
|
+
extend self
|
4
|
+
|
5
|
+
LOG_EVERY = ENV.fetch('LOG_EVERY') { 2 }.to_i
|
6
|
+
|
7
|
+
RABBITMQ_CLUSTER = ENV.fetch('RABBITMQ_CLUSTER') {
|
8
|
+
"localhost"
|
9
|
+
}.split(",")
|
10
|
+
|
11
|
+
RABBITMQ_PORT = ENV.fetch('RABBITMQ_PORT') { 5672 }
|
12
|
+
RABBITMQ_TIMEOUT = ENV.fetch('RABBITMQ_TIMEOUT') { 1 }.to_i
|
13
|
+
RABBITMQ_USER = ENV.fetch('RABBITMQ_USER') { "guest" }
|
14
|
+
RABBITMQ_PASSWORD = ENV.fetch('RABBITMQ_PASSWORD') { "guest" }
|
15
|
+
RABBITMQ_VHOST = ENV.fetch('RABBITMQ_VHOST') { "/" }
|
16
|
+
RABBITMQ_RECONNECT_IN = ENV.fetch('RABBITMQ_RECONNECT_IN') { 5 }.to_i
|
17
|
+
RABBITMQ_PREFECTH = ENV.fetch('RABBITMQ_PREFECTH') { 100 }.to_i
|
18
|
+
|
19
|
+
def rabbitmq_connection
|
20
|
+
{
|
21
|
+
:host => RABBITMQ_CLUSTER.sample,
|
22
|
+
:port => RABBITMQ_PORT,
|
23
|
+
:vhost => RABBITMQ_VHOST,
|
24
|
+
:user => RABBITMQ_USER,
|
25
|
+
:password => RABBITMQ_PASSWORD,
|
26
|
+
:timeout => RABBITMQ_TIMEOUT
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'amqp'
|
2
|
+
|
3
|
+
require_relative 'config'
|
4
|
+
require_relative 'helpers'
|
5
|
+
|
6
|
+
module RoMQ
|
7
|
+
class Connection
|
8
|
+
include Helpers
|
9
|
+
|
10
|
+
def initialize(&block)
|
11
|
+
stop_gracefully
|
12
|
+
|
13
|
+
EM.run do
|
14
|
+
flush_logs_periodically.()
|
15
|
+
|
16
|
+
connection = Config.rabbitmq_connection
|
17
|
+
@amqp_connection = AMQP.connect(connection)
|
18
|
+
|
19
|
+
@amqp_connection.on_error do |channel, connection_close|
|
20
|
+
raise channel_close.reply_text
|
21
|
+
end
|
22
|
+
|
23
|
+
@amqp_connection.on_open do
|
24
|
+
logger.info("[RoMQ] connected to #{connection[:host]}")
|
25
|
+
@amqp_connection.on_tcp_connection_loss do
|
26
|
+
reconnect.(block)
|
27
|
+
end
|
28
|
+
|
29
|
+
channel = AMQP::Channel.new(@amqp_connection, auto_recovery: true)
|
30
|
+
channel.on_error(&handle_channel_error)
|
31
|
+
channel.prefetch(Config::RABBITMQ_PREFECTH)
|
32
|
+
|
33
|
+
yield(channel)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue AMQP::TCPConnectionFailed
|
37
|
+
reconnect.(block)
|
38
|
+
rescue AMQP::PossibleAuthenticationFailureError
|
39
|
+
logger.info("[RoMQ] could not authenticate, check your credentials: #{@amqp_connection.settings}")
|
40
|
+
stop.()
|
41
|
+
end
|
42
|
+
|
43
|
+
def reconnect
|
44
|
+
Proc.new do |block|
|
45
|
+
logger.info("[RoMQ] will try to re-connect in #{Config::RABBITMQ_RECONNECT_IN} seconds...")
|
46
|
+
EM.stop if EM.reactor_running?
|
47
|
+
sleep Config::RABBITMQ_RECONNECT_IN
|
48
|
+
Connection.new(&block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def stop
|
53
|
+
Proc.new do
|
54
|
+
if @amqp_connection and @amqp_connection.connected?
|
55
|
+
@amqp_connection.disconnect do
|
56
|
+
logger.info("[RoMQ] closed connection to #{@amqp_connection.settings[:host]}")
|
57
|
+
super
|
58
|
+
end
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_channel_error
|
66
|
+
Proc.new do |channel, channel_close|
|
67
|
+
logger.error("[RoMQ] channel-level exception")
|
68
|
+
logger.error("[RoMQ] AMQP class id : #{channel_close.class_id}")
|
69
|
+
logger.error("[RoMQ] AMQP method id: #{channel_close.method_id}")
|
70
|
+
logger.error("[RoMQ] Status code : #{channel_close.reply_code}")
|
71
|
+
logger.error("[RoMQ] Error message : #{channel_close.reply_text}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/romq/helpers.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'config'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module RoMQ
|
5
|
+
module Helpers
|
6
|
+
DEBUG = ENV.fetch('DEBUG') { false }
|
7
|
+
|
8
|
+
def flush_logs_periodically
|
9
|
+
Proc.new do |seconds = Config::LOG_EVERY|
|
10
|
+
EM.add_periodic_timer(seconds) do
|
11
|
+
EM.defer { $stdout.flush }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
if @connections_to_stop <= 0
|
18
|
+
EM.stop if EM.reactor_running?
|
19
|
+
logger.info("Stopping #{self.class} service... done!")
|
20
|
+
exit 0
|
21
|
+
else
|
22
|
+
logger.info("Waiting on #{@connections_to_stop} connection(s) to close...")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# If you need to tear down any other connections, keep track of
|
27
|
+
# their status via @connections_to_stop
|
28
|
+
def stop_gracefully
|
29
|
+
@connections_to_stop = 0
|
30
|
+
|
31
|
+
Signal.trap "SIGTERM", stop
|
32
|
+
Signal.trap "SIGINT", stop
|
33
|
+
Signal.trap "SIGQUIT", stop
|
34
|
+
end
|
35
|
+
|
36
|
+
def logger
|
37
|
+
return @logger if @logger
|
38
|
+
|
39
|
+
@logger = Logger.new(STDOUT)
|
40
|
+
@logger.level = DEBUG ? Logger::DEBUG : Logger::INFO
|
41
|
+
@logger
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/romq/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: romq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gerhard Lazu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: amqp
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.7
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.7
|
30
|
+
description: Gracefully handle common amqp exceptions for more robust clients.
|
31
|
+
email:
|
32
|
+
- gerhard@lazu.co.uk
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/romq/config.rb
|
38
|
+
- lib/romq/connection.rb
|
39
|
+
- lib/romq/helpers.rb
|
40
|
+
- lib/romq/version.rb
|
41
|
+
- lib/romq.rb
|
42
|
+
- examples/client.rb
|
43
|
+
- Gemfile
|
44
|
+
- README.md
|
45
|
+
homepage: https://github.com/gosquared/romq
|
46
|
+
licenses: []
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.23
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Cluster-aware amqp client library, never gives up on reconnecting.
|
69
|
+
test_files: []
|