rservicebus2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +64 -0
  3. data/bin/return_messages_to_source_queue +114 -0
  4. data/bin/rsb_ctl +38 -0
  5. data/bin/rservicebus2 +14 -0
  6. data/bin/rservicebus2-create +107 -0
  7. data/bin/rservicebus2-init +104 -0
  8. data/bin/rservicebus2-transport +16 -0
  9. data/bin/send_empty_message +15 -0
  10. data/lib/rservicebus.rb +59 -0
  11. data/lib/rservicebus/agent.rb +54 -0
  12. data/lib/rservicebus/appresource.rb +65 -0
  13. data/lib/rservicebus/appresource/dir.rb +29 -0
  14. data/lib/rservicebus/appresource/file.rb +8 -0
  15. data/lib/rservicebus/appresource/fluiddb.rb +24 -0
  16. data/lib/rservicebus/appresource_configure.rb +33 -0
  17. data/lib/rservicebus/audit.rb +28 -0
  18. data/lib/rservicebus/circuitbreaker.rb +79 -0
  19. data/lib/rservicebus/config.rb +168 -0
  20. data/lib/rservicebus/cron_manager.rb +76 -0
  21. data/lib/rservicebus/endpointmapping.rb +72 -0
  22. data/lib/rservicebus/errormessage.rb +14 -0
  23. data/lib/rservicebus/handler_loader.rb +162 -0
  24. data/lib/rservicebus/handler_manager.rb +131 -0
  25. data/lib/rservicebus/helper_functions.rb +85 -0
  26. data/lib/rservicebus/host.rb +487 -0
  27. data/lib/rservicebus/message.rb +78 -0
  28. data/lib/rservicebus/message/statisticoutput.rb +7 -0
  29. data/lib/rservicebus/message/subscription.rb +10 -0
  30. data/lib/rservicebus/message/verboseoutput.rb +7 -0
  31. data/lib/rservicebus/monitor.rb +61 -0
  32. data/lib/rservicebus/monitor/csvdir.rb +52 -0
  33. data/lib/rservicebus/monitor/dir.rb +139 -0
  34. data/lib/rservicebus/monitor/dirnotifier.rb +101 -0
  35. data/lib/rservicebus/monitor/message.rb +11 -0
  36. data/lib/rservicebus/monitor/xmldir.rb +11 -0
  37. data/lib/rservicebus/monitor_configure.rb +71 -0
  38. data/lib/rservicebus/mq.rb +98 -0
  39. data/lib/rservicebus/mq/beanstalk.rb +72 -0
  40. data/lib/rservicebus/resource_manager.rb +69 -0
  41. data/lib/rservicebus/saga/base.rb +17 -0
  42. data/lib/rservicebus/saga/data.rb +20 -0
  43. data/lib/rservicebus/saga/manager.rb +128 -0
  44. data/lib/rservicebus/saga_loader.rb +118 -0
  45. data/lib/rservicebus/saga_storage.rb +18 -0
  46. data/lib/rservicebus/saga_storage/dir.rb +87 -0
  47. data/lib/rservicebus/saga_storage/inmemory.rb +37 -0
  48. data/lib/rservicebus/sendat_manager.rb +33 -0
  49. data/lib/rservicebus/sendat_storage.rb +20 -0
  50. data/lib/rservicebus/sendat_storage/file.rb +37 -0
  51. data/lib/rservicebus/sendat_storage/inmemory.rb +20 -0
  52. data/lib/rservicebus/state_manager.rb +30 -0
  53. data/lib/rservicebus/state_storage.rb +18 -0
  54. data/lib/rservicebus/state_storage/dir.rb +66 -0
  55. data/lib/rservicebus/state_storage/inmemory.rb +25 -0
  56. data/lib/rservicebus/statistic_manager.rb +86 -0
  57. data/lib/rservicebus/stats.rb +68 -0
  58. data/lib/rservicebus/subscription_manager.rb +31 -0
  59. data/lib/rservicebus/subscription_storage.rb +39 -0
  60. data/lib/rservicebus/subscription_storage/file.rb +42 -0
  61. data/lib/rservicebus/subscription_storage/redis.rb +69 -0
  62. data/lib/rservicebus/subscription_storage_configure.rb +19 -0
  63. data/lib/rservicebus/test.rb +2 -0
  64. data/lib/rservicebus/test/bus.rb +32 -0
  65. data/lib/rservicebus/transporter.rb +142 -0
  66. data/lib/rservicebus/usermessage/withpayload.rb +10 -0
  67. metadata +184 -0
@@ -0,0 +1,85 @@
1
+ module RServiceBus
2
+ def self.convert_dto_to_hash(obj)
3
+ hash = {}
4
+ obj.instance_variables.each do |var|
5
+ hash[var.to_s.delete('@')] = obj.instance_variable_get(var)
6
+ end
7
+ hash
8
+ end
9
+
10
+ def self.convert_dto_to_json(obj)
11
+ convert_dto_to_hash(obj).to_json
12
+ end
13
+
14
+ def self.log(string, ver = false)
15
+ return if check_environment_variable('TESTING')
16
+
17
+ type = ver ? 'VERB' : 'INFO'
18
+ if check_environment_variable('VERBOSE') || !ver
19
+ timestamp = Time.new.strftime('%Y-%m-%d %H:%M:%S')
20
+ puts "[#{type}] #{timestamp} :: #{string}"
21
+ end
22
+ end
23
+
24
+ def self.rlog(string)
25
+ return unless check_environment_variable('RSBVERBOSE')
26
+
27
+ timestamp = Time.new.strftime('%Y-%m-%d %H:%M:%S')
28
+ puts "[RSB] #{timestamp} :: #{string}"
29
+ end
30
+
31
+ def self.create_anonymous_class(name_for_class)
32
+ new_anonymous_class = Class.new(Object)
33
+ Object.const_set(name_for_class, new_anonymous_class)
34
+ Object.const_get(name_for_class).new
35
+ end
36
+
37
+ def self.get_value(name, default = nil)
38
+ value = (ENV[name].nil? || ENV[name] == '') ? default : ENV[name]
39
+ log "Env value: #{name}: #{value}"
40
+ value
41
+ end
42
+
43
+ def self.send_msg(msg, response_queue = 'agent')
44
+ require 'rservicebus/endpointmapping'
45
+ endpoint_mapping = EndpointMapping.new
46
+ endpoint_mapping.configure
47
+ queue_name = endpoint_mapping.get(msg.class.name)
48
+
49
+ ENV['RSBMQ'] = 'beanstalk://localhost' if ENV['RSBMQ'].nil?
50
+ agent = RServiceBus::Agent.new
51
+ Audit.new(agent).audit_to_queue(msg)
52
+ agent.send_msg(msg, queue_name, response_queue)
53
+
54
+ rescue QueueNotFoundForMsg => e
55
+ msg = "\n"
56
+ msg = "#{msg}*** Queue not found for, #{e.message}\n"
57
+ msg = "#{msg}*** Ensure you have an environment variable set for this
58
+ Message Type, eg, \n"
59
+ msg = "#{msg}*** MESSAGE_ENDPOINT_MAPPINGS=#{e.message}:<QueueName>\n"
60
+ raise StandardError, msg
61
+ end
62
+
63
+ def self.check_for_reply(queue_name)
64
+ ENV['RSBMQ'] = 'beanstalk://localhost' if ENV['RSBMQ'].nil?
65
+ agent = RServiceBus::Agent.new
66
+ msg = agent.check_for_reply(queue_name)
67
+ Audit.new(agent).audit_incoming(msg)
68
+
69
+ msg
70
+ end
71
+
72
+ def self.tick(string)
73
+ puts "[TICK] #{Time.new.strftime('%Y-%m-%d %H:%M:%S.%6N')} ::
74
+ #{caller[0]}. #{string}"
75
+ end
76
+
77
+ def self.check_environment_variable(string)
78
+ return false if ENV[string].nil?
79
+ return true if ENV[string] == true || ENV[string] =~ (/(true|t|yes|y|1)$/i)
80
+ return false if ENV[string] == false ||
81
+ ENV[string].nil? ||
82
+ ENV[string] =~ (/(false|f|no|n|0)$/i)
83
+ fail ArgumentError, "invalid value for Environment Variable: \"#{string}\""
84
+ end
85
+ end
@@ -0,0 +1,487 @@
1
+ module RServiceBus
2
+ class NoHandlerFound < StandardError
3
+ end
4
+ class ClassNotFoundForMsg < StandardError
5
+ end
6
+ class NoMsgToProcess < StandardError
7
+ end
8
+ class PropertyNotSet < StandardError
9
+ end
10
+
11
+ # Host process for rservicebus
12
+ class Host
13
+ attr_accessor :sagaData
14
+
15
+ # Provides a thin logging veneer
16
+ # @param [String] string Log entry
17
+ # @param [Boolean] ver Indicator for a verbose log entry
18
+ def log(string, ver = false)
19
+ RServiceBus.log(string, ver)
20
+ end
21
+
22
+ # Thin veneer for Configuring external resources
23
+ def configure_app_resource
24
+ @resource_manager = ConfigureAppResource.new
25
+ .get_resources(ENV,
26
+ self,
27
+ @state_manager,
28
+ @saga_storage)
29
+ self
30
+ end
31
+
32
+ # Thin veneer for Configuring SendAt
33
+ def configure_send_at_manager
34
+ @send_at_manager = SendAtManager.new(self)
35
+ self
36
+ end
37
+
38
+ # Thin veneer for Configuring state
39
+ def configure_state_manager
40
+ @state_manager = StateManager.new
41
+ self
42
+ end
43
+
44
+ # Thin veneer for Configuring state
45
+ def configure_saga_storage
46
+ string = RServiceBus.get_value('SAGA_URI')
47
+ string = 'dir:///tmp' if string.nil?
48
+
49
+ uri = URI.parse(string)
50
+ @saga_storage = SagaStorage.get(uri)
51
+ self
52
+ end
53
+
54
+ # Thin veneer for Configuring Cron
55
+ def configure_circuit_breaker
56
+ @circuit_breaker = CircuitBreaker.new(self)
57
+ self
58
+ end
59
+
60
+ # Thin veneer for Configuring external resources
61
+ def configure_monitors
62
+ @monitors = ConfigureMonitor.new(self, @resource_manager).get_monitors(ENV)
63
+ self
64
+ end
65
+
66
+ # Thin veneer for Configuring the Message Queue
67
+ def connect_to_mq
68
+ @mq = MQ.get
69
+ self
70
+ end
71
+
72
+ # Subscriptions are specified by adding events to the
73
+ # msg endpoint mapping
74
+ def send_subscriptions
75
+ log 'Send Subscriptions'
76
+
77
+ @endpoint_mapping.get_subscription_endpoints.each do |event_name|
78
+ subscribe(event_name)
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ # Load and configure Message Handlers
85
+ def load_handlers
86
+ log 'Load Message Handlers'
87
+ @handler_manager = HandlerManager.new(self, @resource_manager, @state_manager)
88
+ @handler_loader = HandlerLoader.new(self, @handler_manager)
89
+
90
+ @config.handler_path_list.each do |path|
91
+ @handler_loader.load_handlers_from_path(path)
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ # Load and configure Sagas
98
+ def load_sagas
99
+ log 'Load Sagas'
100
+ @saga_manager = SagaManager.new(self, @resource_manager, @saga_storage)
101
+ @saga_loader = SagaLoader.new(self, @saga_manager)
102
+
103
+ @config.saga_path_list.each do |path|
104
+ @saga_loader.load_sagas_from_path(path)
105
+ end
106
+
107
+ self
108
+ end
109
+
110
+ # Thin veneer for Configuring Cron
111
+ def configure_cron_manager
112
+ @cron_manager = CronManager.new(self, @handler_manager.get_list_of_msg_names)
113
+ self
114
+ end
115
+
116
+ # Load Contracts
117
+ def load_contracts
118
+ log 'Load Contracts'
119
+
120
+ @config.contract_list.each do |path|
121
+ require path
122
+ RServiceBus.rlog "Loaded Contract: #{path}"
123
+ end
124
+
125
+ self
126
+ end
127
+
128
+ # For each directory given, find and load all librarys
129
+ def load_libs
130
+ log 'Load Libs'
131
+ @config.lib_list.each do |path|
132
+ $:.unshift path
133
+ end
134
+
135
+ self
136
+ end
137
+
138
+ # Load, configure and initialise Subscriptions
139
+ def configure_subscriptions
140
+ subscription_storage = ConfigureSubscriptionStorage.new.get(@config.app_name, @config.subscription_uri)
141
+ @subscription_manager = SubscriptionManager.new(subscription_storage)
142
+ self
143
+ end
144
+
145
+ # Initialise statistics monitor
146
+ def configure_statistics
147
+ @stats = StatisticManager.new( self )
148
+ self
149
+ end
150
+
151
+ def initialize
152
+ RServiceBus.rlog "Current directory: #{Dir.pwd}"
153
+ @config = ConfigFromEnv.new.load_host_section
154
+ .load_contracts
155
+ .load_handler_path_list
156
+ .load_saga_path_list
157
+ .load_libs
158
+ .load_working_dir_list
159
+
160
+ connect_to_mq
161
+
162
+ @endpoint_mapping = EndpointMapping.new.configure(@mq.local_queue_name)
163
+
164
+ self.configure_statistics
165
+ .load_contracts
166
+ .load_libs
167
+ .configure_send_at_manager
168
+ .configure_state_manager
169
+ .configure_saga_storage
170
+ .configure_app_resource
171
+ .configure_circuit_breaker
172
+ .configure_monitors
173
+ .load_handlers
174
+ .load_sagas
175
+ .configure_cron_manager
176
+ .configure_subscriptions
177
+ .send_subscriptions
178
+
179
+ self
180
+ end
181
+
182
+ # Ignition
183
+ def run
184
+ log 'Starting the Host'
185
+ log "Watching, #{@mq.local_queue_name}"
186
+ $0 = "rservicebus - #{@mq.local_queue_name}"
187
+ unless @config.forward_received_messages_to.nil?
188
+ log 'Forwarding all received messages to: ' + @config.forward_received_messages_to.to_s
189
+ end
190
+ unless @config.forward_sent_messages_to.nil?
191
+ log 'Forwarding all sent messages to: ' + @config.forward_sent_messages_to.to_s
192
+ end
193
+
194
+ start_listening_to_endpoints
195
+ end
196
+
197
+ # Receive a msg, prep it, and handle any errors that may occur
198
+ # - Most of this should be queue independant
199
+ def start_listening_to_endpoints
200
+ log 'Waiting for messages. To exit press CTRL+C'
201
+ message_loop = true
202
+ retries = @config.max_retries
203
+
204
+ while message_loop
205
+ # Popping a msg off the queue should not be in the message handler,
206
+ # as it affects retry
207
+ begin
208
+ @stats.tick
209
+ if @circuit_breaker.broken
210
+ sleep 0.5
211
+ next
212
+ end
213
+
214
+ body = @mq.pop
215
+ begin
216
+ @stats.inc_total_processed
217
+ @msg = YAML.load(body)
218
+ case @msg.msg.class.name
219
+ when 'RServiceBus::MessageSubscription'
220
+ @subscription_manager.add(@msg.msg.event_name,
221
+ @msg.return_address)
222
+ when 'RServiceBus::MessageStatisticOutputOn'
223
+ @stats.output = true
224
+ log 'Turn on Stats logging'
225
+ when 'RServiceBus::MessageStatisticOutputOff'
226
+ @stats.output = false
227
+ log 'Turn off Stats logging'
228
+ when 'RServiceBus::MessageVerboseOutputOn'
229
+ ENV['VERBOSE'] = 'true'
230
+ log 'Turn on Verbose logging'
231
+ when 'RServiceBus::MessageVerboseOutputOff'
232
+ ENV.delete('VERBOSE')
233
+ log 'Turn off Verbose logging'
234
+ else
235
+ handle_message
236
+ unless @config.forward_received_messages_to.nil?
237
+ _send_already_wrapped_and_serialised(body, @config.forward_received_messages_to)
238
+ end
239
+ end
240
+ @mq.ack
241
+ rescue ClassNotFoundForMsg => e
242
+ puts "*** Class not found for msg, #{e.message}"
243
+ puts "*** Ensure, #{e.message}, is defined in Contract.rb, most
244
+ likely as 'Class #{e.message} end"
245
+
246
+ @msg.add_error_msg(@mq.local_queue_name, e.message)
247
+ serialized_object = YAML.dump(@msg)
248
+ _send_already_wrapped_and_serialised(serialized_object,
249
+ @config.error_queue_name)
250
+ @mq.ack
251
+ rescue NoHandlerFound => e
252
+ puts "*** Handler not found for msg, #{e.message}"
253
+ puts "*** Ensure a handler named, #{e.message}, is present in the
254
+ MessageHandler directory."
255
+
256
+ @msg.add_error_msg(@mq.local_queue_name, e.message)
257
+ serialized_object = YAML.dump(@msg)
258
+ _send_already_wrapped_and_serialised(serialized_object,
259
+ @config.error_queue_name)
260
+ @mq.ack
261
+
262
+ rescue PropertyNotSet => e
263
+ # This has been re-rasied from a rescue in the handler
264
+ puts "*** #{e.message}"
265
+ # "Property, #{e.message}, not set for, #{handler.class.name}"
266
+ property_name = e.message[10, e.message.index(',', 10) - 10]
267
+ puts "*** Ensure the environment variable, RSB_#{property_name},
268
+ has been set at startup."
269
+
270
+ rescue StandardError => e
271
+ sleep 0.5
272
+
273
+ puts '*** Exception occurred'
274
+ puts e.message
275
+ puts e.backtrace
276
+ puts '***'
277
+
278
+ if retries > 0
279
+ retries -= 1
280
+ @mq.return_to_queue
281
+ else
282
+ @circuit_breaker.failure
283
+ @stats.inc_total_errored
284
+ if e.class.name == 'Beanstalk::NotConnected'
285
+ puts 'Lost connection to beanstalkd.'
286
+ puts '*** Start or Restart beanstalkd and try again.'
287
+ abort
288
+ end
289
+
290
+ if e.class.name == 'Redis::CannotConnectError'
291
+ puts 'Lost connection to redis.'
292
+ puts '*** Start or Restart redis and try again.'
293
+ abort
294
+ end
295
+
296
+ error_string = e.message + '. ' + e.backtrace.join('. ')
297
+ @msg.add_error_msg(@mq.local_queue_name, error_string)
298
+ serialized_object = YAML.dump(@msg)
299
+ _send_already_wrapped_and_serialised(serialized_object, @config.error_queue_name)
300
+ @mq.ack
301
+ retries = @config.max_retries
302
+ end
303
+ end
304
+ rescue SystemExit, Interrupt
305
+ puts 'Exiting on request ...'
306
+ message_loop = false
307
+ rescue NoMsgToProcess => e
308
+ # This exception is just saying there are no messages to process
309
+ @queue_for_msgs_to_be_sent_on_complete = []
310
+ @monitors.each(&:look)
311
+ send_queued_msgs
312
+ @queue_for_msgs_to_be_sent_on_complete = nil
313
+
314
+ @queue_for_msgs_to_be_sent_on_complete = []
315
+ @cron_manager.run
316
+ send_queued_msgs
317
+ @queue_for_msgs_to_be_sent_on_complete = nil
318
+
319
+ @send_at_manager.process
320
+ @circuit_breaker.success
321
+
322
+ rescue StandardError => e
323
+ if e.message == 'SIGTERM' || e.message == 'SIGINT'
324
+ puts 'Exiting on request ...'
325
+ message_loop = false
326
+ else
327
+ puts '*** This is really unexpected.'
328
+ message_loop = false
329
+ puts 'Message: ' + e.message
330
+ puts e.backtrace
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ # Send the current msg to the appropriate handlers
337
+ def handle_message
338
+ @resource_manager.begin
339
+ msg_name = @msg.msg.class.name
340
+ handler_list = @handler_manager.get_handler_list_for_msg(msg_name)
341
+ RServiceBus.rlog 'Handler found for: ' + msg_name
342
+ begin
343
+ @queue_for_msgs_to_be_sent_on_complete = []
344
+
345
+ log "Started processing msg, #{msg_name}"
346
+ handler_list.each do |handler|
347
+ begin
348
+ log "Handler, #{handler.class.name}, Started"
349
+ handler.handle(@msg.msg)
350
+ log "Handler, #{handler.class.name}, Finished"
351
+ rescue PropertyNotSet => e
352
+ raise PropertyNotSet.new( "Property, #{e.message}, not set for, #{handler.class.name}" )
353
+ rescue StandardError => e
354
+ puts "E #{e.message}"
355
+ log 'An error occurred in Handler: ' + handler.class.name
356
+ raise e
357
+ end
358
+ end
359
+
360
+ if @saga_manager.handle(@msg) == false && handler_list.length == 0
361
+ fail NoHandlerFound, msg_name
362
+ end
363
+ @resource_manager.commit(msg_name)
364
+
365
+ send_queued_msgs
366
+ log "Finished processing msg, #{msg_name}"
367
+
368
+ rescue StandardError => e
369
+ @resource_manager.rollback(msg_name)
370
+ @queue_for_msgs_to_be_sent_on_complete = nil
371
+ raise e
372
+ end
373
+ end
374
+
375
+ #######################################################################################################
376
+ # All msg sending Methods
377
+
378
+ # Sends a msg across the bus
379
+ # @param [String] serialized_object serialized RServiceBus::Message
380
+ # @param [String] queue_name endpoint to which the msg will be sent
381
+ def _send_already_wrapped_and_serialised(serialized_object, queue_name)
382
+ RServiceBus.rlog 'Bus._send_already_wrapped_and_serialised'
383
+
384
+ unless @config.forward_sent_messages_to.nil?
385
+ @mq.send(@config.forward_sent_messages_to, serialized_object)
386
+ end
387
+
388
+ @mq.send(queue_name, serialized_object)
389
+ end
390
+
391
+ # Sends a msg across the bus
392
+ # @param [RServiceBus::Message] msg msg to be sent
393
+ # @param [String] queueName endpoint to which the msg will be sent
394
+ def _send_needs_wrapping(msg, queue_name, correlation_id)
395
+ RServiceBus.rlog 'Bus._send_needs_wrapping'
396
+
397
+ r_msg = RServiceBus::Message.new(msg, @mq.local_queue_name, correlation_id)
398
+ if queue_name.index('@').nil?
399
+ q = queue_name
400
+ RServiceBus.rlog "Sending, #{msg.class.name} to, #{queue_name}"
401
+ else
402
+ parts = queue_name.split('@')
403
+ r_msg.set_remote_queue_name(parts[0])
404
+ r_msg.set_remote_host_name(parts[1])
405
+ q = 'transport-out'
406
+ RServiceBus.rlog "Sending, #{msg.class.name} to, #{queue_name}, via #{q}"
407
+ end
408
+
409
+ serialized_object = YAML.dump(r_msg)
410
+ _send_already_wrapped_and_serialised(serialized_object, q)
411
+ end
412
+
413
+ def send_queued_msgs
414
+ @queue_for_msgs_to_be_sent_on_complete.each do |row|
415
+ if row['timestamp'].nil?
416
+ _send_needs_wrapping(row['msg'], row['queue_name'], row['correlation_id'])
417
+ else
418
+ @send_at_manager.add(row)
419
+ end
420
+ end
421
+ end
422
+
423
+ def queue_msg_for_send_on_complete(msg, queue_name, timestamp = nil)
424
+ correlation_id = @saga_data.nil? ? nil : @saga_data.correlation_id
425
+ correlation_id = (!@msg.nil? && !@msg.correlation_id.nil?) ? @msg.correlation_id : correlation_id
426
+ @queue_for_msgs_to_be_sent_on_complete << Hash['msg', msg, 'queue_name', queue_name, 'correlation_id', correlation_id, 'timestamp',timestamp ]
427
+ end
428
+
429
+ # Sends a msg back across the bus
430
+ # Reply queues are specified in each msg. It works like
431
+ # email, where the reply address can actually be anywhere
432
+ # @param [RServiceBus::Message] msg msg to be sent
433
+ def reply(msg)
434
+ RServiceBus.rlog 'Reply with: ' + msg.class.name + ' To: ' + @msg.return_address
435
+ @stats.inc_total_reply
436
+
437
+ queue_msg_for_send_on_complete(msg, @msg.return_address)
438
+ end
439
+
440
+ def get_endpoint_for_msg(msg_name)
441
+ queue_name = @endpoint_mapping.get(msg_name)
442
+ return queue_name unless queue_name.nil?
443
+
444
+ return @mq.local_queue_name if @handler_manager.can_msg_be_handled_locally(msg_name)
445
+
446
+ log 'No end point mapping found for: ' + msg_name
447
+ log '**** Check environment variable MessageEndpointMappings contains an entry named : ' + msg_name
448
+ raise 'No end point mapping found for: ' + msg_name
449
+ end
450
+
451
+
452
+ # Send a msg across the bus
453
+ # msg destination is specified at the infrastructure level
454
+ # @param [RServiceBus::Message] msg msg to be sent
455
+ def send( msg, timestamp=nil )
456
+ RServiceBus.rlog 'Bus.Send'
457
+ @stats.inc_total_sent
458
+
459
+ msg_name = msg.class.name
460
+ queue_name = self.get_endpoint_for_msg(msg_name)
461
+ queue_msg_for_send_on_complete(msg, queue_name, timestamp)
462
+ end
463
+
464
+ # Sends an event to all subscribers across the bus
465
+ # @param [RServiceBus::Message] msg msg to be sent
466
+ def publish(msg)
467
+ RServiceBus.rlog 'Bus.Publish'
468
+ @stats.inc_total_published
469
+
470
+ subscriptions = @subscription_manager.get(msg.class.name)
471
+ subscriptions.each do |subscriber|
472
+ queue_msg_for_send_on_complete(msg, subscriber)
473
+ end
474
+ end
475
+
476
+ # Sends a subscription request across the Bus
477
+ # @param [String] eventName event to be subscribes to
478
+ def subscribe(event_name)
479
+ RServiceBus.rlog 'Bus.Subscribe: ' + event_name
480
+
481
+ queue_name = get_endpoint_for_msg(event_name)
482
+ subscription = MessageSubscription.new(event_name)
483
+
484
+ _send_needs_wrapping(subscription, queue_name, nil)
485
+ end
486
+ end
487
+ end