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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/README.mediawiki +169 -0
  3. data/Rakefile +24 -0
  4. data/bin/console +11 -0
  5. data/bin/messagebus_swarm +77 -0
  6. data/lib/messagebus.rb +62 -0
  7. data/lib/messagebus/client.rb +166 -0
  8. data/lib/messagebus/cluster_map.rb +161 -0
  9. data/lib/messagebus/connection.rb +118 -0
  10. data/lib/messagebus/consumer.rb +447 -0
  11. data/lib/messagebus/custom_errors.rb +37 -0
  12. data/lib/messagebus/dottable_hash.rb +113 -0
  13. data/lib/messagebus/error_status.rb +42 -0
  14. data/lib/messagebus/logger.rb +45 -0
  15. data/lib/messagebus/message.rb +168 -0
  16. data/lib/messagebus/messagebus_types.rb +107 -0
  17. data/lib/messagebus/producer.rb +187 -0
  18. data/lib/messagebus/swarm.rb +49 -0
  19. data/lib/messagebus/swarm/controller.rb +296 -0
  20. data/lib/messagebus/swarm/drone.rb +195 -0
  21. data/lib/messagebus/swarm/drone/logging_worker.rb +53 -0
  22. data/lib/messagebus/validations.rb +68 -0
  23. data/lib/messagebus/version.rb +36 -0
  24. data/messagebus.gemspec +29 -0
  25. data/spec/messagebus/client_spec.rb +157 -0
  26. data/spec/messagebus/cluster_map_spec.rb +178 -0
  27. data/spec/messagebus/consumer_spec.rb +338 -0
  28. data/spec/messagebus/dottable_hash_spec.rb +137 -0
  29. data/spec/messagebus/message_spec.rb +93 -0
  30. data/spec/messagebus/producer_spec.rb +147 -0
  31. data/spec/messagebus/swarm/controller_spec.rb +73 -0
  32. data/spec/messagebus/validations_spec.rb +71 -0
  33. data/spec/spec_helper.rb +10 -0
  34. data/vendor/gems/stomp.rb +23 -0
  35. data/vendor/gems/stomp/client.rb +360 -0
  36. data/vendor/gems/stomp/connection.rb +583 -0
  37. data/vendor/gems/stomp/errors.rb +39 -0
  38. data/vendor/gems/stomp/ext/hash.rb +24 -0
  39. data/vendor/gems/stomp/message.rb +68 -0
  40. metadata +138 -0
@@ -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
@@ -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.
@@ -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
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ base = File.dirname(__FILE__)
4
+ $:.unshift File.expand_path(File.join(base, "..", "lib"))
5
+
6
+ require "irb"
7
+ require "yaml"
8
+ require "messagebus"
9
+
10
+ IRB.start
11
+
@@ -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
@@ -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