mbus 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/README.mediawiki +169 -0
- data/Rakefile +24 -0
- data/bin/console +11 -0
- data/bin/messagebus_swarm +77 -0
- data/lib/messagebus.rb +62 -0
- data/lib/messagebus/client.rb +166 -0
- data/lib/messagebus/cluster_map.rb +161 -0
- data/lib/messagebus/connection.rb +118 -0
- data/lib/messagebus/consumer.rb +447 -0
- data/lib/messagebus/custom_errors.rb +37 -0
- data/lib/messagebus/dottable_hash.rb +113 -0
- data/lib/messagebus/error_status.rb +42 -0
- data/lib/messagebus/logger.rb +45 -0
- data/lib/messagebus/message.rb +168 -0
- data/lib/messagebus/messagebus_types.rb +107 -0
- data/lib/messagebus/producer.rb +187 -0
- data/lib/messagebus/swarm.rb +49 -0
- data/lib/messagebus/swarm/controller.rb +296 -0
- data/lib/messagebus/swarm/drone.rb +195 -0
- data/lib/messagebus/swarm/drone/logging_worker.rb +53 -0
- data/lib/messagebus/validations.rb +68 -0
- data/lib/messagebus/version.rb +36 -0
- data/messagebus.gemspec +29 -0
- data/spec/messagebus/client_spec.rb +157 -0
- data/spec/messagebus/cluster_map_spec.rb +178 -0
- data/spec/messagebus/consumer_spec.rb +338 -0
- data/spec/messagebus/dottable_hash_spec.rb +137 -0
- data/spec/messagebus/message_spec.rb +93 -0
- data/spec/messagebus/producer_spec.rb +147 -0
- data/spec/messagebus/swarm/controller_spec.rb +73 -0
- data/spec/messagebus/validations_spec.rb +71 -0
- data/spec/spec_helper.rb +10 -0
- data/vendor/gems/stomp.rb +23 -0
- data/vendor/gems/stomp/client.rb +360 -0
- data/vendor/gems/stomp/connection.rb +583 -0
- data/vendor/gems/stomp/errors.rb +39 -0
- data/vendor/gems/stomp/ext/hash.rb +24 -0
- data/vendor/gems/stomp/message.rb +68 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 689df9b9f0b86245507faeda6239d9ca24ff2cf1
|
4
|
+
data.tar.gz: 6e95ce8920e6f92951dc28dd967e7049d16ad160
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9d8ada5f134ebf4c992d831ac28ad3cc786c40172c22e1279668afbf774858daeb8f7f9b03dd55ad549cff0ab91b36972c74630e16535f8735ea97b6ed80d19c
|
7
|
+
data.tar.gz: cdfe47c4cfbaa25d92a072cd67776b2aa0ff79f145223176c71764154a4845f3be32d0ff2fed93d4c1f357d2d7b0d4dcbcddb2fb37fc6c7ab39bc2c86c27e4a6
|
data/README.mediawiki
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
= Messagebus =
|
2
|
+
|
3
|
+
A gem for publishing and consuming hornetq messagebus messages.
|
4
|
+
|
5
|
+
== Installation ==
|
6
|
+
|
7
|
+
$ gem install mbus
|
8
|
+
|
9
|
+
== Dependencies ==
|
10
|
+
|
11
|
+
This Gem depends upon the following:
|
12
|
+
|
13
|
+
=== Runtime ===
|
14
|
+
|
15
|
+
* messagebus (vendored an old version for now)
|
16
|
+
* thrift
|
17
|
+
* json
|
18
|
+
|
19
|
+
=== Development & Tests ===
|
20
|
+
|
21
|
+
* bundle install
|
22
|
+
* Execute rspec spec
|
23
|
+
|
24
|
+
== Configuration ==
|
25
|
+
|
26
|
+
The messagebus is configured via a single yaml file. The configuration fields are defined below and an
|
27
|
+
example of a full configuration also provided.
|
28
|
+
|
29
|
+
* enable_auto_init_connections: turn on producer connections once initialized
|
30
|
+
* log_file: path for log
|
31
|
+
* log_level: logger level minimum
|
32
|
+
* logger: pass a logger directly to the messagebus client
|
33
|
+
* worker_log_file: path for worker log
|
34
|
+
* cluster_defaults
|
35
|
+
** user: hornetq user
|
36
|
+
** passwd: hornetq password
|
37
|
+
** receipt_wait_timeout_ms: TODO
|
38
|
+
** conn_lifetime_sec: TODO
|
39
|
+
* clusters: array of haproxy clusters
|
40
|
+
** type: producer-cluster or consumer-cluster
|
41
|
+
** address: host and port of haproxy delimited by colon
|
42
|
+
** destinations: array of queue and topic destinations
|
43
|
+
* swarm_config
|
44
|
+
** fork: true or false -- whether to use forks or threads when booting drones
|
45
|
+
* workers
|
46
|
+
** destination: the destination name
|
47
|
+
** worker: the worker class to process messages with
|
48
|
+
** subscription_id: swarm_drone_run_spec_id
|
49
|
+
** ack_on_error: whether to send an ack for a job that failed
|
50
|
+
** drones: number of drones to boot up for parallel processing
|
51
|
+
|
52
|
+
'''Example config'''
|
53
|
+
enable_auto_init_connections: true
|
54
|
+
log_file: log/messagebus-client.log
|
55
|
+
worker_log_file: log/messagebus-consumer.log
|
56
|
+
|
57
|
+
:swarm_config:
|
58
|
+
# :fork: true
|
59
|
+
|
60
|
+
:workers:
|
61
|
+
-
|
62
|
+
:destination: jms.topic.testTopic2
|
63
|
+
:worker: SimpleDroneRunSpecWorker
|
64
|
+
:subscription_id: swarm_drone_run_spec_id
|
65
|
+
|
66
|
+
:ack_on_error: false
|
67
|
+
:drones: 1
|
68
|
+
|
69
|
+
:cluster_defaults:
|
70
|
+
:user: guest
|
71
|
+
:passwd: guest
|
72
|
+
:receipt_wait_timeout_ms: 1500
|
73
|
+
:conn_lifetime_sec: 300
|
74
|
+
:enable_dynamic_serverlist_fetch: true
|
75
|
+
|
76
|
+
clusters:
|
77
|
+
-
|
78
|
+
name: orders-messagebus-cluster
|
79
|
+
producer_address: localhost:61613
|
80
|
+
consumer_address: localhost:61613
|
81
|
+
destinations:
|
82
|
+
- jms.topic.testTopic2
|
83
|
+
|
84
|
+
== Getting Started ==
|
85
|
+
|
86
|
+
You will find an example listed of loading a configuration, instantiation of a client, and
|
87
|
+
finally invocation of the publish method. There are three different message types that can
|
88
|
+
be published on the bus, string, binary, or json. An example of each are listed with concrete
|
89
|
+
code to use.
|
90
|
+
|
91
|
+
In its current state, the messagebus gem should be vendored into your application. This will
|
92
|
+
change once the internal rubygems server is integrated into the company. For now, unpack the
|
93
|
+
gem and include "thrift" 0.9.0 into your Gemfile next to the messagebus declaration.
|
94
|
+
|
95
|
+
=== Edit Gemfile ===
|
96
|
+
|
97
|
+
gem "thrift", "0.9.0"
|
98
|
+
gem "messagebus", "x.x.x", :path => "vendor/gems/messagebus-x.x.x", :require => "messagebus"
|
99
|
+
|
100
|
+
|
101
|
+
=== Bundle your gems ===
|
102
|
+
|
103
|
+
$ bundle
|
104
|
+
|
105
|
+
== Producing Messages ==
|
106
|
+
=== Run interactive ruby ===
|
107
|
+
|
108
|
+
$ irb
|
109
|
+
|
110
|
+
ruby>
|
111
|
+
require "messagebus" # Notice this will happen by default in the bundler
|
112
|
+
|
113
|
+
ruby>
|
114
|
+
binary_to_publish = "\xfe\x3e\x5e"
|
115
|
+
config = YAML.load_file("./config/messagebus.yml")
|
116
|
+
client = Messagebus::Client.new(config.merge(:logger => Logger.new("a/directory/to/my/file.log")))
|
117
|
+
client.start
|
118
|
+
client.publish "jms.queue.testQueue1", binary_to_publish
|
119
|
+
|
120
|
+
ruby>
|
121
|
+
string_to_publish = "the quick brown fox jumped over the lazy dogs back"
|
122
|
+
config = YAML.load_file("./config/messagebus.yml")
|
123
|
+
client = Messagebus::Client.new(config.merge(:logger => Logger.new("a/directory/to/my/file.log")))
|
124
|
+
client.publish "jms.queue.testQueue1", string_to_publish
|
125
|
+
|
126
|
+
ruby>
|
127
|
+
hash_to_publish = { :ruby => { :loves => :the_bus } }
|
128
|
+
config = YAML.load_file("./config/messagebus.yml")
|
129
|
+
client = Messagebus::Client.new(config.merge(:logger => Logger.new("a/directory/to/my/file.log")))
|
130
|
+
client.publish "jms.queue.testQueue1", hash_to_publish
|
131
|
+
|
132
|
+
ruby>
|
133
|
+
object_to_publish = DomainObjectThatRespondsToToJson # object_to_publish.to_json will happen automatically
|
134
|
+
config = YAML.load_file("./config/messagebus.yml")
|
135
|
+
client = Messagebus::Client.new(config.merge(:logger => Logger.new("a/directory/to/my/file.log")))
|
136
|
+
client.publish "jms.queue.testQueue1", object_to_publish
|
137
|
+
|
138
|
+
=== Watch Tail Processing Log ===
|
139
|
+
|
140
|
+
The tail will start displaying new log messages.
|
141
|
+
|
142
|
+
$ tail -f log/messagebus-client.log
|
143
|
+
|
144
|
+
|
145
|
+
== Consuming messages ==
|
146
|
+
You have 2 options. Option 1 is write your own consumer class. See [[https://github.com/groupon/Message-Bus/blob/master/mbus-ruby/examples/consumer_topic_example.rb|consumer_topic_example.rb]]
|
147
|
+
for how to write your own consumer.
|
148
|
+
|
149
|
+
Your other option is to use the Message Swarm code. Try examples/swarm_example.sh. See [[https://github.com/groupon/Message-Bus/wiki/Swarm-Consumer|Swarm Guide]] for more on that.
|
150
|
+
|
151
|
+
== More detail needed? ==
|
152
|
+
|
153
|
+
Contact us via email! dpe@groupon.com
|
154
|
+
|
155
|
+
If something is not behaving intuitively, it is a bug and should be reported.
|
156
|
+
Report it here: https://github.groupon.com/data-infrastructure/ruby-messagebus
|
157
|
+
|
158
|
+
== Note on Patches/Pull Requests ==
|
159
|
+
|
160
|
+
* Fork the project.
|
161
|
+
* Make your feature addition or bug fix.
|
162
|
+
* Commit, do not mess with rakefile, version, or history.
|
163
|
+
* Send me a pull request. Bonus points for topic branches.
|
164
|
+
|
165
|
+
== Copyright ==
|
166
|
+
|
167
|
+
Copyright (c) 2011 Groupon. Released under the MIT License.
|
168
|
+
|
169
|
+
See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rubygems/package_task"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
|
5
|
+
SPEC = begin
|
6
|
+
file = File.expand_path(File.dirname(__FILE__) + '/messagebus.gemspec')
|
7
|
+
eval(File.read(file), binding, file)
|
8
|
+
end
|
9
|
+
|
10
|
+
Gem::PackageTask.new(SPEC) {}
|
11
|
+
|
12
|
+
desc "Run all specs"
|
13
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
14
|
+
t.rspec_opts = %w[--color --format=progress]
|
15
|
+
t.pattern = 'spec/**/*_spec.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run code coverage"
|
19
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
20
|
+
t.rspec_opts = %w[--color --format=progress]
|
21
|
+
t.rcov = true
|
22
|
+
t.rcov_opts = %w[--exclude='gems,spec']
|
23
|
+
t.pattern = 'spec/**/*_spec.rb'
|
24
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
|
5
|
+
require 'messagebus'
|
6
|
+
require 'messagebus/swarm/controller'
|
7
|
+
|
8
|
+
options = {
|
9
|
+
:requires => [],
|
10
|
+
:configuration_source => Messagebus::Swarm::Controller::ConfigurationSource.new(:default, nil)
|
11
|
+
}
|
12
|
+
|
13
|
+
parser = OptionParser.new do |opts|
|
14
|
+
opts.banner = "Usage: swarm [options] COMMAND"
|
15
|
+
|
16
|
+
opts.separator ""
|
17
|
+
opts.separator "Options:"
|
18
|
+
|
19
|
+
opts.on("--config_path PATH", "A path to a yaml configuration file") do |config_path|
|
20
|
+
options[:configuration_source] = Messagebus::Swarm::Controller::ConfigurationSource.new(:path, config_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("--config_eval RUBY_CODE", "Ruby that evaluates to a configuration hash. This is ran after any requires") do |config_eval|
|
24
|
+
options[:configuration_source] = Messagebus::Swarm::Controller::ConfigurationSource.new(:eval, config_eval)
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-h", "--help", "Show help message") do
|
28
|
+
puts opts
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-r", "--require FILE", "A file to require before starting the swarm. Repeatable.") do |file|
|
32
|
+
options[:requires] << file
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("--pidfile PID_FILE", "A file to write the PID to") do |file|
|
36
|
+
options[:pidfile] = file
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.separator ""
|
40
|
+
opts.separator "Commands:"
|
41
|
+
opts.separator " start Start all workers in the configuration"
|
42
|
+
opts.separator " start DESTINATION COUNT Start COUNT workers for DESTINATION swarm listeners"
|
43
|
+
opts.separator " stop pid Kill a swarm"
|
44
|
+
opts.separator ""
|
45
|
+
end
|
46
|
+
|
47
|
+
parser.parse!
|
48
|
+
|
49
|
+
Messagebus::Swarm::Controller.require_files(options[:requires])
|
50
|
+
if pidfile = options[:pidfile]
|
51
|
+
pid = Process.pid
|
52
|
+
Messagebus::Swarm::Controller.write_pid(pidfile)
|
53
|
+
at_exit do
|
54
|
+
# we need this check to make sure we only bother doing this if
|
55
|
+
# we are the parent process that's shutting down
|
56
|
+
# at_exit is carried down when forking
|
57
|
+
Messagebus::Swarm::Controller.delete_pid(pidfile) if Process.pid == pid
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
case ARGV[0]
|
62
|
+
when 'start'
|
63
|
+
destination_name, drone_count = ARGV[1], ARGV[2]
|
64
|
+
|
65
|
+
log_file = options[:configuration_source].configuration_hash["worker_log_file"]
|
66
|
+
logger = log_file ? Logger.new(log_file) : Messagebus::Client.logger
|
67
|
+
|
68
|
+
Messagebus::Swarm::Controller.start(options[:configuration_source], logger, destination_name, drone_count)
|
69
|
+
exit(0)
|
70
|
+
when 'stop'
|
71
|
+
pid = ARGV[1] or raise "Must specify a pid of the process to stop"
|
72
|
+
Messagebus::Swarm::Controller.stop(pid.to_i)
|
73
|
+
exit(0)
|
74
|
+
else
|
75
|
+
puts parser.help
|
76
|
+
exit(1)
|
77
|
+
end
|
data/lib/messagebus.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright (c) 2012, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "vendor/gems"))
|
32
|
+
|
33
|
+
require "messagebus/version"
|
34
|
+
require 'messagebus/logger'
|
35
|
+
require 'messagebus/message'
|
36
|
+
require "messagebus/messagebus_types"
|
37
|
+
require 'messagebus/custom_errors'
|
38
|
+
require 'messagebus/error_status'
|
39
|
+
require 'messagebus/validations'
|
40
|
+
require 'messagebus/connection'
|
41
|
+
require 'messagebus/producer'
|
42
|
+
require 'messagebus/consumer'
|
43
|
+
require 'messagebus/cluster_map'
|
44
|
+
require 'messagebus/client'
|
45
|
+
|
46
|
+
require 'thrift'
|
47
|
+
require 'base64'
|
48
|
+
require 'stomp'
|
49
|
+
|
50
|
+
module Messagebus
|
51
|
+
# These are deprecated and not used anymore
|
52
|
+
DEST_TYPE_QUEUE = 'queue'
|
53
|
+
DEST_TYPE_TOPIC = 'topic'
|
54
|
+
|
55
|
+
ACK_TYPE_AUTO_CLIENT = 'autoClient'
|
56
|
+
ACK_TYPE_CLIENT = 'client'
|
57
|
+
|
58
|
+
LOG_DEFAULT_FILE = '/tmp/messagebus_client.log'
|
59
|
+
|
60
|
+
SERVER_REGEX = /^[a-zA-Z0-9\_.-]+:[0-9]+$/
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# Copyright (c) 2012, Groupon, Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of GROUPON nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
20
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
21
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
22
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
25
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
26
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
27
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
29
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
require "messagebus/dottable_hash"
|
32
|
+
require "benchmark"
|
33
|
+
require "logger"
|
34
|
+
|
35
|
+
module Messagebus
|
36
|
+
class Client
|
37
|
+
class InvalidDestinationError < StandardError; end
|
38
|
+
class InitializationError < StandardError; end
|
39
|
+
|
40
|
+
attr_reader :config, :logger, :cluster_map, :last_reload_time
|
41
|
+
|
42
|
+
def self.start(config_hash)
|
43
|
+
client = new(config_hash)
|
44
|
+
client.start
|
45
|
+
|
46
|
+
if block_given?
|
47
|
+
begin
|
48
|
+
yield client
|
49
|
+
ensure
|
50
|
+
client.stop
|
51
|
+
end
|
52
|
+
end
|
53
|
+
client
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(config_hash)
|
57
|
+
|
58
|
+
@@logger = if provided_logger = config_hash.delete(:logger)
|
59
|
+
provided_logger
|
60
|
+
elsif log_file = config_hash["log_file"]
|
61
|
+
Logger.new(log_file)
|
62
|
+
else
|
63
|
+
Logger.new(Messagebus::LOG_DEFAULT_FILE)
|
64
|
+
end
|
65
|
+
|
66
|
+
# This is required to do a deep clone of config hash object
|
67
|
+
@config = DottableHash.new(Marshal.load(Marshal.dump(config_hash)))
|
68
|
+
@config.merge!(@config.cluster_defaults) if @config.cluster_defaults
|
69
|
+
@@logger.level = Logger::Severity.const_get(@config.log_level.upcase) if @config.log_level
|
70
|
+
|
71
|
+
@enable_client_logger_thread_debugging = config.enable_client_logger_thread_debugging
|
72
|
+
|
73
|
+
logger.debug "Initializing Messagebus client."
|
74
|
+
@cluster_map = ClusterMap.new(@config)
|
75
|
+
#added for reloading config on interval
|
76
|
+
@last_reload_time = Time.now
|
77
|
+
end
|
78
|
+
|
79
|
+
# Starts up all the connections to the bus.
|
80
|
+
# Optionally takes a block to which it yields self. When the block is
|
81
|
+
# passed, it will auto close the connections after the block finishes.
|
82
|
+
def start
|
83
|
+
if @config.enable_auto_init_connections
|
84
|
+
logger.info "auto enable connections set, starting clusters."
|
85
|
+
@cluster_map.start
|
86
|
+
else
|
87
|
+
logger.info "Config['enable_auto_init_connections'] is false, will not start any messagebus producers."
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop
|
92
|
+
cluster_map.stop
|
93
|
+
end
|
94
|
+
|
95
|
+
def logger
|
96
|
+
@@logger ||= @config['log_file'] ? Logger.new(@config['log_file']) : Logger.new(Messagebus::LOG_DEFAULT_FILE)
|
97
|
+
end
|
98
|
+
|
99
|
+
def publish(destination_name, object, delay_ms = 0, safe = true, binary = false, headers = {})
|
100
|
+
|
101
|
+
if !(@config.enable_auto_init_connections)
|
102
|
+
logger.warn "Config['enable_auto_init_connections'] is false, not publishing destination_name=#{destination_name}, message_contents=#{object.inspect}"
|
103
|
+
false
|
104
|
+
else
|
105
|
+
producer = cluster_map.find(destination_name)
|
106
|
+
if producer.nil?
|
107
|
+
logger.error "Not publishing due to unconfigured destionation name. destination_name=#{destination_name}, message=#{object.inspect}"
|
108
|
+
raise InvalidDestinationError, "Destination #{destination_name} not found"
|
109
|
+
end
|
110
|
+
|
111
|
+
if binary
|
112
|
+
message = Messagebus::Message.create(object, nil, binary)
|
113
|
+
else
|
114
|
+
message = Messagebus::Message.create(object)
|
115
|
+
end
|
116
|
+
|
117
|
+
logger.info "Publishing to destination_name=#{destination_name}, message_id=#{message.message_id}, message_contents=#{object.inspect}"
|
118
|
+
|
119
|
+
begin
|
120
|
+
publish_result = nil
|
121
|
+
duration = Benchmark.realtime do
|
122
|
+
publish_result = producer.publish(destination_name, message, headers(delay_ms).merge(headers), safe)
|
123
|
+
end
|
124
|
+
duration = (duration * 1_000).round
|
125
|
+
|
126
|
+
if publish_result
|
127
|
+
logger.info "Message publishing to #{destination_name} took #{duration} result=success destination_name=#{destination_name}, message_id=#{message.message_id}, duration=#{duration}ms"
|
128
|
+
true
|
129
|
+
else
|
130
|
+
logger.error "Failed to publish message result=fail destination_name=#{destination_name}, message_id=#{message.message_id}, duration=#{duration}ms, message_contents=#{object.inspect}"
|
131
|
+
false
|
132
|
+
end
|
133
|
+
rescue => e
|
134
|
+
logger.error "Failed to publish message result=error destination_name=#{destination_name}, message_id=#{message.message_id}, duration=#{duration}ms, message_contents=#{object.inspect}, error=#{e.inspect}, backtrace=#{e.backtrace.join("|")}"
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def reload_config_on_interval(config, interval = 300)
|
141
|
+
logger.info "Relaoding client configs after interval=#{interval}"
|
142
|
+
now = Time.now
|
143
|
+
if(now - @last_reload_time) >= interval
|
144
|
+
@cluster_map.update_config(config)
|
145
|
+
@last_reload_time = now
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def headers(delay)
|
150
|
+
headers = {}
|
151
|
+
unless delay == 0
|
152
|
+
schedule_time = (Time.now.to_i * 1000 + delay).to_s
|
153
|
+
headers.merge!({
|
154
|
+
Messagebus::Producer::SCHEDULED_DELIVERY_TIME_MS_HEADER => schedule_time
|
155
|
+
})
|
156
|
+
end
|
157
|
+
headers
|
158
|
+
end
|
159
|
+
|
160
|
+
class << self
|
161
|
+
def logger
|
162
|
+
@@logger ||= Logger.new(Messagebus::LOG_DEFAULT_FILE)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|