acception-subscriber 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +3 -0
- data/README.md +21 -0
- data/Rakefile +2 -0
- data/acception-subscriber.gemspec +32 -0
- data/bin/acception-sub +4 -0
- data/lib/acception-subscriber.rb +1 -0
- data/lib/acception/subscriber.rb +39 -0
- data/lib/acception/subscriber/cli.rb +132 -0
- data/lib/acception/subscriber/configuration.rb +48 -0
- data/lib/acception/subscriber/logging.rb +23 -0
- data/lib/acception/subscriber/message_handler.rb +119 -0
- data/lib/acception/subscriber/publish_error.rb +7 -0
- data/lib/acception/subscriber/server.rb +118 -0
- data/lib/acception/subscriber/server_daemon.rb +146 -0
- data/lib/acception/subscriber/server_logging.rb +81 -0
- data/lib/acception/subscriber/version.rb +7 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 77f56d09784b6c9d77a986455b5f18f8a0ae55e7
|
4
|
+
data.tar.gz: 46026ce3b88d330b1aaf6d89027ba948365f71e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: caa67f69a4f6f13b3dfd5904e2aada8ebb9adfb5c38f0959df561871128c1d7012ea37aa4eb3cb6f2e172293132945ac914537aa1834ecbed0373ef3c61cb034
|
7
|
+
data.tar.gz: b6d0c9e860e241b3c7c08f275a7460b1547500e5aaea1412087b58ebb130fe2223d7860e8f8650be9c5be676890f58305303f4d335edc75fc12f28ed3489c6b6
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
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
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
acception-subscriber
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.0
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
source 'http://dev.staging.iberon.com/gemserver'
|
3
|
+
|
4
|
+
# Specify your gem's dependencies in replication-subscriber.gemspec
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
group :development do
|
8
|
+
gem 'rake-iberon', '~> 1', require: false
|
9
|
+
end
|
10
|
+
|
11
|
+
#gem 'acception-client', path: '../acception-client'
|
data/LICENSE.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Acception::Subscriber
|
2
|
+
|
3
|
+
A RabbitMQ subscriber that pushes messages to Acception's API.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'acception-subscriber'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install acception-subscriber
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'acception/subscriber/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "acception-subscriber"
|
8
|
+
spec.version = Acception::Subscriber::VERSION
|
9
|
+
spec.authors = ["C. Jason Harrelson"]
|
10
|
+
spec.email = ["cjharrelson@iberon.com"]
|
11
|
+
spec.summary = %q{A RabbitMQ subscriber that pushes messages to Acception's API.}
|
12
|
+
spec.description = %q{A RabbitMQ subscriber that pushes messages to Acception's API. See README for more details.}
|
13
|
+
spec.homepage = "https://gitlab.staging.iberon.com/common/acception-subscriber"
|
14
|
+
spec.license = ""
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = 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.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_dependency "acception-client", ">= 1.2"
|
25
|
+
spec.add_dependency "bunny", "~> 1"
|
26
|
+
spec.add_dependency "celluloid", "~> 0"
|
27
|
+
spec.add_dependency "multi_json", "~> 1"
|
28
|
+
spec.add_dependency "oj", "~> 2"
|
29
|
+
spec.add_dependency "trollop", "~> 2"
|
30
|
+
spec.add_dependency "yell", "~> 1"
|
31
|
+
|
32
|
+
end
|
data/bin/acception-sub
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'acception/subscriber'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'ansi'
|
2
|
+
require "acception/client"
|
3
|
+
require "acception/subscriber/version"
|
4
|
+
|
5
|
+
module Acception
|
6
|
+
module Subscriber
|
7
|
+
|
8
|
+
autoload :Configuration, 'acception/subscriber/configuration'
|
9
|
+
autoload :Logging, 'acception/subscriber/logging'
|
10
|
+
autoload :MessageHandler, 'acception/subscriber/message_handler'
|
11
|
+
autoload :Server, 'acception/subscriber/server'
|
12
|
+
autoload :ServerDaemon, 'acception/subscriber/server_daemon'
|
13
|
+
autoload :ServerLogging, 'acception/subscriber/server_logging'
|
14
|
+
|
15
|
+
APP_ID = "acception-sub"
|
16
|
+
APP_NAME = "Acception Subscriber"
|
17
|
+
COMPANY = "Iberon, LLC"
|
18
|
+
INT = "INT"
|
19
|
+
TERM = "TERM"
|
20
|
+
VERSION_COPYRIGHT = "v#{VERSION} \u00A9#{Time.now.year} #{COMPANY}"
|
21
|
+
|
22
|
+
def self.configuration
|
23
|
+
@configuration ||= Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configuration=( configuration )
|
27
|
+
@configuration = configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configure
|
31
|
+
yield( configuration ) if block_given?
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
attr_accessor :logger
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'acception/subscriber'
|
3
|
+
require 'trollop'
|
4
|
+
require 'yell'
|
5
|
+
|
6
|
+
module Acception
|
7
|
+
module Subscriber
|
8
|
+
class Cli
|
9
|
+
|
10
|
+
attr_reader :cmd,
|
11
|
+
:options
|
12
|
+
|
13
|
+
SUB_COMMANDS = %w(
|
14
|
+
restart
|
15
|
+
start
|
16
|
+
status
|
17
|
+
stop
|
18
|
+
)
|
19
|
+
|
20
|
+
DEFAULT_CONFIG_PATH = "/etc/ncite/#{APP_ID}.conf"
|
21
|
+
DEFAULT_LOG_PATH = "/var/log/ncite/#{APP_ID}.log"
|
22
|
+
DEFAULT_PID_PATH = "/var/run/ncite/#{APP_ID}.pid"
|
23
|
+
|
24
|
+
DEFAULT_NUMBER_OF_THREADS = 1
|
25
|
+
|
26
|
+
def initialize( args )
|
27
|
+
Trollop::options do
|
28
|
+
version VERSION_COPYRIGHT
|
29
|
+
banner <<-EOS
|
30
|
+
#{APP_NAME} #{VERSION_COPYRIGHT}
|
31
|
+
|
32
|
+
Usage:
|
33
|
+
#{APP_ID} [command] [options]
|
34
|
+
|
35
|
+
commands:
|
36
|
+
#{SUB_COMMANDS.map { |sub_cmd| " #{sub_cmd}" }.join( "\n" )}
|
37
|
+
|
38
|
+
(For help with a command: #{APP_ID} [command] -h)
|
39
|
+
|
40
|
+
options:
|
41
|
+
EOS
|
42
|
+
stop_on SUB_COMMANDS
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get the sub-command and its options
|
46
|
+
#
|
47
|
+
@cmd = ARGV.shift || ''
|
48
|
+
@options = case( cmd )
|
49
|
+
when "restart"
|
50
|
+
Trollop::options do
|
51
|
+
opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
|
52
|
+
opt :log_level, "The log level", :type => String, :default => 'info'
|
53
|
+
opt :log_level, "The log level", :type => String, :default => 'info', :short => '-o'
|
54
|
+
opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
|
55
|
+
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
56
|
+
opt :threads, "The number of threads", :type => Integer, :default => DEFAULT_NUMBER_OF_THREADS, :short => '-t'
|
57
|
+
end
|
58
|
+
when "start"
|
59
|
+
Trollop::options do
|
60
|
+
opt :config, "The path for the config file", :type => String, :short => '-c', :default => DEFAULT_CONFIG_PATH
|
61
|
+
opt :interactive, "Execute the server in interactive mode", :short => '-i'
|
62
|
+
opt :log_level, "The log level", :type => String, :default => 'info', :short => '-o'
|
63
|
+
opt :log, "The path for the log file", :type => String, :short => '-l', :default => DEFAULT_LOG_PATH
|
64
|
+
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
65
|
+
opt :threads, "The number of threads", :type => Integer, :default => DEFAULT_NUMBER_OF_THREADS, :short => '-t'
|
66
|
+
end
|
67
|
+
when "status"
|
68
|
+
Trollop::options do
|
69
|
+
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
70
|
+
end
|
71
|
+
when "stop"
|
72
|
+
Trollop::options do
|
73
|
+
opt :pid, "The path for the PID file", :type => String, :default => DEFAULT_PID_PATH
|
74
|
+
end
|
75
|
+
else
|
76
|
+
Trollop::die "unknown command #{cmd.inspect}"
|
77
|
+
end
|
78
|
+
|
79
|
+
if cmd == 'start'
|
80
|
+
unless options[:interactive]
|
81
|
+
Trollop::die( :config, "is required when running as daemon" ) unless options[:config]
|
82
|
+
Trollop::die( :log, "is required when running as daemon" ) unless options[:log]
|
83
|
+
Trollop::die( :pid, "is required when running as daemon" ) unless options[:pid]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if %w(restart status stop).include?( cmd )
|
88
|
+
Trollop::die( :pid, "is required" ) unless options[:pid]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def run
|
93
|
+
send( cmd )
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def start
|
99
|
+
if options[:interactive]
|
100
|
+
start_interactive
|
101
|
+
else
|
102
|
+
start_daemon
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def start_interactive
|
107
|
+
server = Acception::Subscriber::Server.new( options.merge( log: nil ))
|
108
|
+
server.start
|
109
|
+
end
|
110
|
+
|
111
|
+
def start_daemon
|
112
|
+
server = Acception::Subscriber::ServerDaemon.new( options )
|
113
|
+
server.start
|
114
|
+
end
|
115
|
+
|
116
|
+
def stop
|
117
|
+
server = Acception::Subscriber::ServerDaemon.new( options )
|
118
|
+
server.stop
|
119
|
+
end
|
120
|
+
|
121
|
+
def restart
|
122
|
+
stop
|
123
|
+
start_daemon
|
124
|
+
end
|
125
|
+
|
126
|
+
def status
|
127
|
+
Acception::Subscriber::ServerDaemon.new( options ).status
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'oj'
|
2
|
+
|
3
|
+
module Acception
|
4
|
+
module Subscriber
|
5
|
+
class Configuration
|
6
|
+
|
7
|
+
def self.attributes
|
8
|
+
%w(
|
9
|
+
acception_auth_token
|
10
|
+
acception_url
|
11
|
+
host_uri
|
12
|
+
queue
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor( *attributes )
|
17
|
+
|
18
|
+
def self.from_file( file_path )
|
19
|
+
options = Oj.load( File.read( file_path ))
|
20
|
+
Acception::Subscriber.configuration = Configuration.new
|
21
|
+
|
22
|
+
attributes.each do |c|
|
23
|
+
if options[c]
|
24
|
+
Acception::Subscriber.configuration.send( :"#{c}=", options[c] )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def acception_auth_token
|
30
|
+
@acception_auth_token || "00-6TKIMQF4NZA"
|
31
|
+
end
|
32
|
+
|
33
|
+
def acception_url
|
34
|
+
@acception_url || "http://localhost:3004"
|
35
|
+
end
|
36
|
+
|
37
|
+
def host_uri
|
38
|
+
@host_uri || "amqp://guest:guest@127.0.0.1:5672"
|
39
|
+
end
|
40
|
+
|
41
|
+
def queue
|
42
|
+
#@queue || "error-repo"
|
43
|
+
@queue || "error"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Acception
|
2
|
+
module Subscriber
|
3
|
+
module Logging
|
4
|
+
|
5
|
+
%w(
|
6
|
+
debug
|
7
|
+
error
|
8
|
+
fatal
|
9
|
+
info
|
10
|
+
warn
|
11
|
+
).each do |level|
|
12
|
+
|
13
|
+
define_method level do |*messages|
|
14
|
+
messages.each do |message|
|
15
|
+
Acception::Subscriber.logger.send level, message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'celluloid/autostart'
|
2
|
+
require 'oj'
|
3
|
+
|
4
|
+
module Acception
|
5
|
+
module Subscriber
|
6
|
+
class MessageHandler
|
7
|
+
|
8
|
+
include Celluloid
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
BLANK = '<<blank>>'
|
12
|
+
ERROR = 'error'
|
13
|
+
LICENSE_VIOLATION = 'license-violation'
|
14
|
+
REQUEUE = true
|
15
|
+
|
16
|
+
def call( options )
|
17
|
+
channel = options[:channel]
|
18
|
+
delivery_info = options[:delivery_info]
|
19
|
+
payload = options[:payload]
|
20
|
+
metadata = options[:metadata]
|
21
|
+
headers = metadata[:headers]
|
22
|
+
|
23
|
+
debug ANSI.cyan { 'HEADERS' } + " #{headers}"
|
24
|
+
debug ANSI.yellow { 'PAYLOAD' } + " #{payload}"
|
25
|
+
|
26
|
+
case resolve_type( payload )
|
27
|
+
when ERROR
|
28
|
+
handle_error( headers )
|
29
|
+
when LICENSE_VIOLATION
|
30
|
+
handle_license_violation( headers )
|
31
|
+
else
|
32
|
+
end
|
33
|
+
|
34
|
+
channel.acknowledge delivery_info.delivery_tag
|
35
|
+
rescue => e
|
36
|
+
debug ANSI.red { "NACK" } + " #{e.message}"
|
37
|
+
debug ANSI.red { "NACK" } + " #{e.backtrace}"
|
38
|
+
#channel.nack delivery_info.delivery_tag
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def handle_error( headers )
|
44
|
+
exception = headers['exception']
|
45
|
+
acception = Acception::Client::OpenMessages::Create.new( message_type: Acception::MessageType::ERROR,
|
46
|
+
application: (headers['application'] || BLANK),
|
47
|
+
environment: (headers['environment'] || BLANK),
|
48
|
+
occurred_at: (headers['occurred_at'] || BLANK),
|
49
|
+
message: (exception['message'] || BLANK),
|
50
|
+
request_headers: (headers['request_headers'] || BLANK),
|
51
|
+
request_parameters: (headers['request_parameters'] || BLANK),
|
52
|
+
session: (headers['session'] || BLANK),
|
53
|
+
type: (exception['class'] || BLANK),
|
54
|
+
stack: (exception['backtrace'] || BLANK) )
|
55
|
+
acception.call
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_license_violation( headers )
|
59
|
+
acception = Acception::Client::OpenMessages::Create.new( message_type: Acception::MessageType::LICENSE_VIOLATION,
|
60
|
+
application: headers['application'],
|
61
|
+
occurred_at: headers['occurred_at'],
|
62
|
+
variables: [
|
63
|
+
{
|
64
|
+
name: 'license-violation-type',
|
65
|
+
content: (headers['type'] || BLANK),
|
66
|
+
content_type: 'text/plain'
|
67
|
+
},
|
68
|
+
{
|
69
|
+
name: 'license-content',
|
70
|
+
content: (headers['content'] || BLANK),
|
71
|
+
content_type: 'application/base64'
|
72
|
+
},
|
73
|
+
{
|
74
|
+
name: 'nonce',
|
75
|
+
content: (headers['nonce'] || BLANK),
|
76
|
+
content_type: 'application/base64'
|
77
|
+
},
|
78
|
+
{
|
79
|
+
name: 'site-private-key',
|
80
|
+
content: (headers['site_private_key'] || BLANK),
|
81
|
+
content_type: 'application/base64'
|
82
|
+
},
|
83
|
+
{
|
84
|
+
name: 'iberon-public-key',
|
85
|
+
content: (headers['iiberon_public_key'] || BLANK),
|
86
|
+
content_type: 'application/base64'
|
87
|
+
}
|
88
|
+
])
|
89
|
+
acception.call
|
90
|
+
end
|
91
|
+
|
92
|
+
def resolve_type( payload )
|
93
|
+
return ERROR if payload == ERROR
|
94
|
+
return LICENSE_VIOLATION if payload == LICENSE_VIOLATION
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
#def handle_error( channel, payload, e )
|
99
|
+
#error( ANSI.red { e.message + " | " + e.backtrace.inspect } )
|
100
|
+
#error_queue( channel ).publish( payload, headers: { application: Acception::Subscriber::APP_ID,
|
101
|
+
#exception_message: e.message,
|
102
|
+
#exception_class: e.class.name,
|
103
|
+
#exception_backtrace: e.backtrace } )
|
104
|
+
#rescue => ex
|
105
|
+
#error( ANSI.red { ex.message + " | " + ex.backtrace.inspect } )
|
106
|
+
#end
|
107
|
+
|
108
|
+
#def requeue( channel, delivery_info, e=nil )
|
109
|
+
#debug ANSI.yellow { 'REQUEUE ' + e.message }
|
110
|
+
#channel.reject delivery_info.delivery_tag, REQUEUE
|
111
|
+
#end
|
112
|
+
|
113
|
+
def config
|
114
|
+
Acception::Subscriber.configuration
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
require 'celluloid'
|
3
|
+
|
4
|
+
module Acception
|
5
|
+
module Subscriber
|
6
|
+
class Server
|
7
|
+
|
8
|
+
include ServerLogging
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
attr_reader :message_consumer,
|
12
|
+
:options
|
13
|
+
|
14
|
+
def initialize( options )
|
15
|
+
@options = options
|
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( host_uri ).tap do |bunny|
|
38
|
+
bunny.start
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def channel
|
43
|
+
@channel ||= mq.create_channel
|
44
|
+
end
|
45
|
+
|
46
|
+
def queue
|
47
|
+
@queue ||= channel.queue( config.queue,
|
48
|
+
durable: true )
|
49
|
+
end
|
50
|
+
|
51
|
+
def pool
|
52
|
+
@pool ||= MessageHandler.pool( size: options[:threads] )
|
53
|
+
end
|
54
|
+
|
55
|
+
def run
|
56
|
+
if options[:threads] == 1
|
57
|
+
Celluloid::Actor[:message_handler] = MessageHandler.new
|
58
|
+
end
|
59
|
+
|
60
|
+
@message_consumer = queue.subscribe( manual_ack: true ) do |delivery_info, metadata, payload|
|
61
|
+
debug ANSI.magenta { "LISTENER RECEIVED #{payload}" }
|
62
|
+
|
63
|
+
if options[:threads] > 1
|
64
|
+
pool.async.call( payload: payload,
|
65
|
+
delivery_info: delivery_info,
|
66
|
+
metadata: metadata,
|
67
|
+
channel: channel )
|
68
|
+
else
|
69
|
+
message_handler.call( payload: payload,
|
70
|
+
delivery_info: delivery_info,
|
71
|
+
metadata: metadata,
|
72
|
+
channel: channel )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def message_handler
|
78
|
+
Celluloid::Actor[:message_handler]
|
79
|
+
end
|
80
|
+
|
81
|
+
def host_uri
|
82
|
+
config.host_uri
|
83
|
+
end
|
84
|
+
|
85
|
+
def config
|
86
|
+
Acception::Subscriber.configuration
|
87
|
+
end
|
88
|
+
|
89
|
+
def configure_server
|
90
|
+
load_configuration
|
91
|
+
configure_acception
|
92
|
+
initialize_loggers
|
93
|
+
end
|
94
|
+
|
95
|
+
def load_configuration
|
96
|
+
if File.exists?( options[:config] )
|
97
|
+
options[:config_loaded] = true
|
98
|
+
Configuration.from_file( options[:config] )
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def configure_acception
|
103
|
+
Acception::Client.configure do |c|
|
104
|
+
c.authentication_token = config.acception_auth_token
|
105
|
+
c.base_url = config.acception_url
|
106
|
+
#c.graceful_errors_map = ServiceErrorHandling::GRACEFUL_ERRORS_MAP
|
107
|
+
c.logger = Acception::Subscriber.logger
|
108
|
+
#c.log_level = options.fetch( :log_level, :info ).to_sym
|
109
|
+
c.open_timeout_in_seconds = 10
|
110
|
+
c.read_timeout_in_seconds = 20
|
111
|
+
#c.retry_attempts = configatron.iols.retry_attempts.to_i || 1
|
112
|
+
#c.retry_sleep = configatron.iols.retry_sleep || false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
module Acception
|
6
|
+
module Subscriber
|
7
|
+
class ServerDaemon
|
8
|
+
|
9
|
+
attr_reader :name,
|
10
|
+
:options,
|
11
|
+
:pid,
|
12
|
+
:pid_path,
|
13
|
+
:script,
|
14
|
+
:timeout
|
15
|
+
|
16
|
+
def initialize( options )
|
17
|
+
@options = options
|
18
|
+
@name = options[:name] || APP_NAME
|
19
|
+
@pid_path = options[:pid] || '.'
|
20
|
+
@pid = get_pid
|
21
|
+
@timeout = options[:timeout] || 10
|
22
|
+
end
|
23
|
+
|
24
|
+
def start
|
25
|
+
abort "Process already running!" if process_exists?
|
26
|
+
|
27
|
+
pid = fork do
|
28
|
+
exit if fork
|
29
|
+
Process.setsid
|
30
|
+
exit if fork
|
31
|
+
store_pid( Process.pid )
|
32
|
+
File.umask 0000
|
33
|
+
redirect_output!
|
34
|
+
run
|
35
|
+
end
|
36
|
+
|
37
|
+
Process.waitpid( pid )
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
Server.new( options ).start
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop
|
45
|
+
kill_process
|
46
|
+
FileUtils.rm pid_path
|
47
|
+
end
|
48
|
+
|
49
|
+
def status
|
50
|
+
out = "#{APP_NAME} "
|
51
|
+
if process_exists?
|
52
|
+
out << "process running with PID: #{pid}"
|
53
|
+
else
|
54
|
+
out << "process does not exist"
|
55
|
+
end
|
56
|
+
$stdout.puts out
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
#def create_pid( pid )
|
62
|
+
def store_pid( pid )
|
63
|
+
File.open( pid_path, 'w' ) do |f|
|
64
|
+
f.puts pid
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
$stderr.puts "Unable to open #{pid_path} for writing:\n\t(#{e.class}) #{e.message}"
|
68
|
+
exit!
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_pid
|
72
|
+
return nil unless File.exists?( pid_path )
|
73
|
+
pid = nil
|
74
|
+
File.open( @pid_path, 'r' ) do |f|
|
75
|
+
pid = f.readline.to_s.gsub( /[^0-9]/, '' )
|
76
|
+
end
|
77
|
+
pid.to_i
|
78
|
+
rescue Errno::ENOENT
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def remove_pidfile
|
83
|
+
File.unlink( pid_path )
|
84
|
+
rescue => e
|
85
|
+
$stderr.puts "Unable to unlink #{pid_path}:\n\t(#{e.class}) #{e.message}"
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
|
89
|
+
def kill_process
|
90
|
+
abort "#{APP_NAME} process is not running" unless process_exists?
|
91
|
+
$stdout.write "Attempting to stop #{APP_NAME} process #{pid}..."
|
92
|
+
Process.kill INT, pid
|
93
|
+
iteration_num = 0
|
94
|
+
while process_exists? && iteration_num < 10
|
95
|
+
sleep 1
|
96
|
+
$stdout.write "."
|
97
|
+
iteration_num += 1
|
98
|
+
end
|
99
|
+
if process_exists?
|
100
|
+
$stderr.puts "\nFailed to stop #{APP_NAME} process #{pid}"
|
101
|
+
else
|
102
|
+
$stdout.puts "\nSuccessfuly stopped #{APP_NAME} process #{pid}"
|
103
|
+
end
|
104
|
+
rescue Errno::EPERM
|
105
|
+
$stderr.puts "No permission to query #{pid}!";
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_exists?
|
109
|
+
return false unless pid
|
110
|
+
Process.kill( 0, pid )
|
111
|
+
true
|
112
|
+
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
|
113
|
+
false
|
114
|
+
rescue Errno::EPERM
|
115
|
+
$stderr.puts "No permission to query #{pid}!";
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
119
|
+
def redirect_output!
|
120
|
+
if log_path = options[:log]
|
121
|
+
#puts "redirecting to log"
|
122
|
+
# if the log directory doesn't exist, create it
|
123
|
+
FileUtils.mkdir_p( File.dirname( log_path ), :mode => 0755 )
|
124
|
+
# touch the log file to create it
|
125
|
+
FileUtils.touch( log_path )
|
126
|
+
# Set permissions on the log file
|
127
|
+
File.chmod( 0644, log_path )
|
128
|
+
# Reopen $stdout (NOT +STDOUT+) to start writing to the log file
|
129
|
+
$stdout.reopen( log_path, 'a' )
|
130
|
+
# Redirect $stderr to $stdout
|
131
|
+
$stderr.reopen $stdout
|
132
|
+
$stdout.sync = true
|
133
|
+
else
|
134
|
+
#puts "redirecting to /dev/null"
|
135
|
+
# We're not bothering to sync if we're dumping to /dev/null
|
136
|
+
# because /dev/null doesn't care about buffered output
|
137
|
+
$stdin.reopen '/dev/null'
|
138
|
+
$stdout.reopen '/dev/null', 'a'
|
139
|
+
$stderr.reopen $stdout
|
140
|
+
end
|
141
|
+
log_path = options[:log] ? options[:log] : '/dev/null'
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'yell'
|
2
|
+
|
3
|
+
# Provides logging services for the base server.
|
4
|
+
#
|
5
|
+
module Acception
|
6
|
+
module Subscriber
|
7
|
+
module ServerLogging
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def initialize_loggers
|
12
|
+
Acception::Subscriber.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
|
+
|
18
|
+
#Celluloid.logger = Yell.new do |l|
|
19
|
+
#l.level = :info
|
20
|
+
#l.adapter :file, File.join( File.dirname( options[:log] ), "#{APP_ID}-celluloid.log" )
|
21
|
+
#end
|
22
|
+
end
|
23
|
+
|
24
|
+
def log_startup
|
25
|
+
start_banner( options ).each do |line|
|
26
|
+
Acception::Subscriber.logger.info line
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def start_banner( options )
|
31
|
+
[
|
32
|
+
"",
|
33
|
+
"***",
|
34
|
+
"* #{APP_NAME} started",
|
35
|
+
"*",
|
36
|
+
"* #{VERSION_COPYRIGHT}",
|
37
|
+
"*",
|
38
|
+
"* Configuration:",
|
39
|
+
(options[:config_loaded] ? "* file: #{options[:config]}" : nil),
|
40
|
+
Acception::Subscriber::Configuration.attributes.map { |a| "* #{a}: #{config_value( a )}" },
|
41
|
+
"*",
|
42
|
+
"***",
|
43
|
+
].flatten.reject( &:nil? )
|
44
|
+
end
|
45
|
+
|
46
|
+
def log_level
|
47
|
+
options.fetch( :log_level, :info ).to_sym
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def config_value( key )
|
52
|
+
value = Acception::Subscriber.configuration.send( key )
|
53
|
+
|
54
|
+
return value unless value.is_a?( Hash )
|
55
|
+
|
56
|
+
return redacted_hash( value )
|
57
|
+
end
|
58
|
+
|
59
|
+
def redacted_hash( hash )
|
60
|
+
redacted_hash = {}
|
61
|
+
|
62
|
+
hash.keys.
|
63
|
+
collect( &:to_s ).
|
64
|
+
grep( /#{redacted_keys}/i ).
|
65
|
+
each do |blacklisted_key|
|
66
|
+
value = hash[blacklisted_key]
|
67
|
+
redacted_hash[blacklisted_key] = value.nil? ? nil : '[REDACTED]'
|
68
|
+
end
|
69
|
+
|
70
|
+
hash.merge( redacted_hash )
|
71
|
+
end
|
72
|
+
|
73
|
+
def redacted_keys
|
74
|
+
%w(
|
75
|
+
password
|
76
|
+
).join( '|' )
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acception-subscriber
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- C. Jason Harrelson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: acception-client
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bunny
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: celluloid
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: multi_json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: oj
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: trollop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '2'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yell
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1'
|
139
|
+
description: A RabbitMQ subscriber that pushes messages to Acception's API. See README
|
140
|
+
for more details.
|
141
|
+
email:
|
142
|
+
- cjharrelson@iberon.com
|
143
|
+
executables:
|
144
|
+
- acception-sub
|
145
|
+
extensions: []
|
146
|
+
extra_rdoc_files: []
|
147
|
+
files:
|
148
|
+
- ".gitignore"
|
149
|
+
- ".ruby-gemset"
|
150
|
+
- ".ruby-version"
|
151
|
+
- Gemfile
|
152
|
+
- LICENSE.txt
|
153
|
+
- README.md
|
154
|
+
- Rakefile
|
155
|
+
- acception-subscriber.gemspec
|
156
|
+
- bin/acception-sub
|
157
|
+
- lib/acception-subscriber.rb
|
158
|
+
- lib/acception/subscriber.rb
|
159
|
+
- lib/acception/subscriber/cli.rb
|
160
|
+
- lib/acception/subscriber/configuration.rb
|
161
|
+
- lib/acception/subscriber/logging.rb
|
162
|
+
- lib/acception/subscriber/message_handler.rb
|
163
|
+
- lib/acception/subscriber/publish_error.rb
|
164
|
+
- lib/acception/subscriber/server.rb
|
165
|
+
- lib/acception/subscriber/server_daemon.rb
|
166
|
+
- lib/acception/subscriber/server_logging.rb
|
167
|
+
- lib/acception/subscriber/version.rb
|
168
|
+
homepage: https://gitlab.staging.iberon.com/common/acception-subscriber
|
169
|
+
licenses:
|
170
|
+
- ''
|
171
|
+
metadata: {}
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project:
|
188
|
+
rubygems_version: 2.2.1
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: A RabbitMQ subscriber that pushes messages to Acception's API.
|
192
|
+
test_files: []
|