mimi-messaging 0.1.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +66 -0
  4. data/README.md +68 -3
  5. data/TODO.md +8 -0
  6. data/docs/Messaging_Layer_Properties.md +141 -0
  7. data/docs/Why_HTTP_is_a_bad_choice.md +20 -0
  8. data/docs/diagrams/Pattern -- Command.drawio +1 -0
  9. data/docs/diagrams/Pattern -- Event direct.drawio +1 -0
  10. data/docs/diagrams/Pattern -- Event with Queue.drawio +1 -0
  11. data/docs/diagrams/Pattern -- Event.drawio +1 -0
  12. data/docs/diagrams/Pattern -- Query.drawio +1 -0
  13. data/docs/img/pattern--command.png +0 -0
  14. data/docs/img/pattern--event-direct.png +0 -0
  15. data/docs/img/pattern--event-using-queue.png +0 -0
  16. data/docs/img/pattern--event.png +0 -0
  17. data/docs/img/pattern--query.png +0 -0
  18. data/examples/basic_event_listener.rb +35 -0
  19. data/examples/basic_request_processor.rb +38 -0
  20. data/examples/using_messaging_low.rb +59 -0
  21. data/examples/using_pure_adapter.rb +62 -0
  22. data/lib/mimi/messaging.rb +429 -92
  23. data/lib/mimi/messaging/adapters.rb +22 -0
  24. data/lib/mimi/messaging/adapters/base.rb +233 -0
  25. data/lib/mimi/messaging/adapters/memory.rb +119 -0
  26. data/lib/mimi/messaging/adapters/test.rb +50 -0
  27. data/lib/mimi/messaging/errors.rb +24 -12
  28. data/lib/mimi/messaging/json_serializer.rb +45 -0
  29. data/lib/mimi/messaging/message.rb +25 -65
  30. data/lib/mimi/messaging/version.rb +3 -1
  31. data/mimi-messaging.gemspec +25 -23
  32. metadata +34 -77
  33. data/lib/mimi/messaging/connection.rb +0 -181
  34. data/lib/mimi/messaging/listener.rb +0 -72
  35. data/lib/mimi/messaging/mock.rb +0 -13
  36. data/lib/mimi/messaging/mock/connection.rb +0 -153
  37. data/lib/mimi/messaging/mock/request.rb +0 -18
  38. data/lib/mimi/messaging/mock/request_processor.rb +0 -92
  39. data/lib/mimi/messaging/model.rb +0 -27
  40. data/lib/mimi/messaging/model_provider.rb +0 -100
  41. data/lib/mimi/messaging/msgpack/msgpack_ext.rb +0 -14
  42. data/lib/mimi/messaging/msgpack/type_packer.rb +0 -104
  43. data/lib/mimi/messaging/notification.rb +0 -35
  44. data/lib/mimi/messaging/provider.rb +0 -48
  45. data/lib/mimi/messaging/request.rb +0 -56
  46. data/lib/mimi/messaging/request_processor.rb +0 -216
  47. data/lib/mimi/messaging/request_processor/context.rb +0 -39
  48. data/lib/mimi/messaging/request_processor/dsl.rb +0 -121
  49. data/lib/tasks/console_ext.rake +0 -6
  50. data/lib/tasks/console_helpers.rb +0 -116
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Mimi
6
+ module Messaging
7
+ #
8
+ # JSON serializer.
9
+ #
10
+ # De/Serializes a message (Hash) from/into a JSON object
11
+ #
12
+ module JsonSerializer
13
+ #
14
+ # Serialize given message into JSON object
15
+ #
16
+ # @param message [Hash]
17
+ # @return [String]
18
+ #
19
+ def self.serialize(message)
20
+ unless message.is_a?(Hash)
21
+ raise ArgumentError, "Invalid message passed to #{self}#serialize, Hash is expected"
22
+ end
23
+
24
+ message.to_json
25
+ rescue StandardError => e
26
+ raise "#{self} failed to serialize a message: #{e}"
27
+ end
28
+
29
+ # Deserializes a JSON into a message
30
+ #
31
+ # @param message [String]
32
+ # @return [Hash]
33
+ #
34
+ def self.deserialize(message)
35
+ unless message.is_a?(String)
36
+ raise ArgumentError, "Invalid message passed to #{self}#deserialize, String is expected"
37
+ end
38
+
39
+ JSON.parse(message)
40
+ rescue StandardError => e
41
+ raise "#{self} failed to deserialize a message: #{e}"
42
+ end
43
+ end # module JsonSerializer
44
+ end # module Messaging
45
+ end # module Mimi
@@ -1,74 +1,34 @@
1
- require 'json'
2
- require 'msgpack'
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Mimi
5
4
  module Messaging
6
- class Message < Hashie::Mash
7
- def self.queue(name, _opts = {})
8
- @queue_name = name
9
- end
10
-
11
- def self.queue_name
12
- @queue_name || default_queue_name
13
- end
14
-
15
- def self.default_queue_name
16
- Mimi::Messaging::RequestProcessor.class_name_to_resource_name(self, 'message')
17
- end
18
-
19
- def self.get(name, data = {}, opts = {})
20
- headers = {
21
- method_name: name.to_s,
22
- Mimi::Messaging::CONTEXT_ID_KEY => Mimi::Messaging.logger.context_id
23
- }
24
- _d, _m, response = Mimi::Messaging.get(
25
- queue_name, encode(data), opts.deep_merge(headers: headers)
26
- )
27
- raise Timeout::Error unless response
28
- message = new(decode(response))
29
- raise RequestError.new(message.error, Message.new(message.params)) if message.error?
30
- message
31
- end
32
-
33
- def self.post(name, data = {}, opts = {})
34
- headers = {
35
- method_name: name.to_s,
36
- Mimi::Messaging::CONTEXT_ID_KEY => Mimi::Messaging.logger.context_id
37
- }
38
- Mimi::Messaging.post(
39
- queue_name, encode(data), opts.deep_merge(headers: headers)
40
- )
41
- end
42
-
43
- def self.add_method(name, &block)
44
- self.class.instance_eval do
45
- define_method(name, &block)
5
+ #
6
+ # A Message is a Hash and additional headers structure.
7
+ #
8
+ class Message < Hash
9
+ attr_reader :headers
10
+
11
+ # Creates a Message out of Hash or another Message.
12
+ #
13
+ # @param message_or_hash [Hash,Message]
14
+ # @param headers [Hash,nil] additional headers to attach to the message
15
+ #
16
+ def initialize(message_or_hash, headers = nil)
17
+ unless message_or_hash.is_a?(Hash) # or a Message
18
+ raise ArgumentError, "Message or Hash is expected as argument"
46
19
  end
47
- end
48
20
 
49
- def self.methods(*names)
50
- names.each do |method_name|
51
- add_method(method_name) do |*params|
52
- get(method_name, *params)
53
- end
54
- add_method("#{method_name}!") do |*params|
55
- post(method_name, *params)
56
- nil
57
- end
58
- end
59
- end
21
+ # copy attributes
22
+ message_or_hash.each { |k, v| self[k] = v.dup }
60
23
 
61
- def self.encode(data)
62
- MessagePack.pack(data) # data.to_json
63
- end
64
-
65
- def self.decode(raw_message)
66
- MessagePack.unpack(raw_message) # JSON.parse(raw_message)
67
- end
68
-
69
- def to_s
70
- to_hash.to_s
24
+ # copy headers
25
+ headers ||= {}
26
+ if message_or_hash.is_a?(Mimi::Messaging::Message)
27
+ @headers = message_or_hash.headers.merge(headers)
28
+ else
29
+ @headers = headers
30
+ end
71
31
  end
72
32
  end # class Message
73
33
  end # module Messaging
74
- end # module Mimi
34
+ end # module Mimi
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mimi
2
4
  module Messaging
3
- VERSION = '0.1.9'.freeze
5
+ VERSION = "1.1.0"
4
6
  end
5
7
  end
@@ -1,39 +1,41 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'mimi/messaging/version'
5
+ require "mimi/messaging/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = 'mimi-messaging'
8
+ spec.name = "mimi-messaging"
8
9
  spec.version = Mimi::Messaging::VERSION
9
- spec.authors = ['Alex Kukushkin']
10
- spec.email = ['alex@kukushk.in']
10
+ spec.authors = ["Alex Kukushkin"]
11
+ spec.email = ["alex@kukushk.in"]
11
12
 
12
- spec.summary = 'Communications via RabbitMQ for mimi'
13
- spec.description = 'Communications via RabbitMQ for mimi'
14
- spec.homepage = 'https://github.com/kukushkin/mimi-messaging'
15
- spec.license = 'MIT'
13
+ spec.summary = "Interservice communication via message bus for microservices"
14
+ spec.description = "Interservice communication via message bus for microservices"
15
+ spec.homepage = "https://github.com/kukushkin/mimi-messaging"
16
+ spec.license = "MIT"
16
17
 
17
18
  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
19
  # delete this section to allow pushing this gem to any host.
19
20
  if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
21
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
21
22
  else
22
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
23
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
24
  end
24
25
 
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = 'exe'
26
+ # Specify which files should be added to the gem when it is released.
27
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
+ end
31
+ spec.bindir = "exe"
27
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ['lib']
33
+ spec.require_paths = ["lib"]
29
34
 
30
- spec.add_dependency 'bunny', '~> 2.9'
31
- spec.add_dependency 'mimi-core', '~> 0.1'
32
- spec.add_dependency 'mimi-logger', '~> 0.2', '>= 0.2.3'
33
- spec.add_dependency 'msgpack', '~> 1.2'
35
+ spec.add_dependency "mimi-core", "~> 1.1"
34
36
 
35
- spec.add_development_dependency 'bundler', '~> 1.11'
36
- spec.add_development_dependency 'pry', '~> 0.10'
37
- spec.add_development_dependency 'rake', '~> 10.0'
38
- spec.add_development_dependency 'rspec', '~> 3.0'
37
+ spec.add_development_dependency "bundler", "~> 2.0"
38
+ spec.add_development_dependency "pry", "~> 0.12"
39
+ spec.add_development_dependency "rake", "~> 10.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
39
41
  end
metadata CHANGED
@@ -1,105 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mimi-messaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-23 00:00:00.000000000 Z
11
+ date: 2019-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bunny
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.9'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.9'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: mimi-core
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: '0.1'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.1'
41
- - !ruby/object:Gem::Dependency
42
- name: mimi-logger
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.2'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 0.2.3
51
- type: :runtime
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - "~>"
56
- - !ruby/object:Gem::Version
57
- version: '0.2'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 0.2.3
61
- - !ruby/object:Gem::Dependency
62
- name: msgpack
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '1.2'
19
+ version: '1.1'
68
20
  type: :runtime
69
21
  prerelease: false
70
22
  version_requirements: !ruby/object:Gem::Requirement
71
23
  requirements:
72
24
  - - "~>"
73
25
  - !ruby/object:Gem::Version
74
- version: '1.2'
26
+ version: '1.1'
75
27
  - !ruby/object:Gem::Dependency
76
28
  name: bundler
77
29
  requirement: !ruby/object:Gem::Requirement
78
30
  requirements:
79
31
  - - "~>"
80
32
  - !ruby/object:Gem::Version
81
- version: '1.11'
33
+ version: '2.0'
82
34
  type: :development
83
35
  prerelease: false
84
36
  version_requirements: !ruby/object:Gem::Requirement
85
37
  requirements:
86
38
  - - "~>"
87
39
  - !ruby/object:Gem::Version
88
- version: '1.11'
40
+ version: '2.0'
89
41
  - !ruby/object:Gem::Dependency
90
42
  name: pry
91
43
  requirement: !ruby/object:Gem::Requirement
92
44
  requirements:
93
45
  - - "~>"
94
46
  - !ruby/object:Gem::Version
95
- version: '0.10'
47
+ version: '0.12'
96
48
  type: :development
97
49
  prerelease: false
98
50
  version_requirements: !ruby/object:Gem::Requirement
99
51
  requirements:
100
52
  - - "~>"
101
53
  - !ruby/object:Gem::Version
102
- version: '0.10'
54
+ version: '0.12'
103
55
  - !ruby/object:Gem::Dependency
104
56
  name: rake
105
57
  requirement: !ruby/object:Gem::Requirement
@@ -128,7 +80,7 @@ dependencies:
128
80
  - - "~>"
129
81
  - !ruby/object:Gem::Version
130
82
  version: '3.0'
131
- description: Communications via RabbitMQ for mimi
83
+ description: Interservice communication via message bus for microservices
132
84
  email:
133
85
  - alex@kukushk.in
134
86
  executables: []
@@ -137,36 +89,41 @@ extra_rdoc_files: []
137
89
  files:
138
90
  - ".gitignore"
139
91
  - ".rspec"
92
+ - ".rubocop.yml"
140
93
  - ".travis.yml"
141
94
  - CODE_OF_CONDUCT.md
142
95
  - Gemfile
143
96
  - LICENSE.txt
144
97
  - README.md
145
98
  - Rakefile
99
+ - TODO.md
146
100
  - bin/console
147
101
  - bin/setup
102
+ - docs/Messaging_Layer_Properties.md
103
+ - docs/Why_HTTP_is_a_bad_choice.md
104
+ - docs/diagrams/Pattern -- Command.drawio
105
+ - docs/diagrams/Pattern -- Event direct.drawio
106
+ - docs/diagrams/Pattern -- Event with Queue.drawio
107
+ - docs/diagrams/Pattern -- Event.drawio
108
+ - docs/diagrams/Pattern -- Query.drawio
109
+ - docs/img/pattern--command.png
110
+ - docs/img/pattern--event-direct.png
111
+ - docs/img/pattern--event-using-queue.png
112
+ - docs/img/pattern--event.png
113
+ - docs/img/pattern--query.png
114
+ - examples/basic_event_listener.rb
115
+ - examples/basic_request_processor.rb
116
+ - examples/using_messaging_low.rb
117
+ - examples/using_pure_adapter.rb
148
118
  - lib/mimi/messaging.rb
149
- - lib/mimi/messaging/connection.rb
119
+ - lib/mimi/messaging/adapters.rb
120
+ - lib/mimi/messaging/adapters/base.rb
121
+ - lib/mimi/messaging/adapters/memory.rb
122
+ - lib/mimi/messaging/adapters/test.rb
150
123
  - lib/mimi/messaging/errors.rb
151
- - lib/mimi/messaging/listener.rb
124
+ - lib/mimi/messaging/json_serializer.rb
152
125
  - lib/mimi/messaging/message.rb
153
- - lib/mimi/messaging/mock.rb
154
- - lib/mimi/messaging/mock/connection.rb
155
- - lib/mimi/messaging/mock/request.rb
156
- - lib/mimi/messaging/mock/request_processor.rb
157
- - lib/mimi/messaging/model.rb
158
- - lib/mimi/messaging/model_provider.rb
159
- - lib/mimi/messaging/msgpack/msgpack_ext.rb
160
- - lib/mimi/messaging/msgpack/type_packer.rb
161
- - lib/mimi/messaging/notification.rb
162
- - lib/mimi/messaging/provider.rb
163
- - lib/mimi/messaging/request.rb
164
- - lib/mimi/messaging/request_processor.rb
165
- - lib/mimi/messaging/request_processor/context.rb
166
- - lib/mimi/messaging/request_processor/dsl.rb
167
126
  - lib/mimi/messaging/version.rb
168
- - lib/tasks/console_ext.rake
169
- - lib/tasks/console_helpers.rb
170
127
  - mimi-messaging.gemspec
171
128
  homepage: https://github.com/kukushkin/mimi-messaging
172
129
  licenses:
@@ -189,8 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
146
  version: '0'
190
147
  requirements: []
191
148
  rubyforge_project:
192
- rubygems_version: 2.6.14.1
149
+ rubygems_version: 2.6.14.4
193
150
  signing_key:
194
151
  specification_version: 4
195
- summary: Communications via RabbitMQ for mimi
152
+ summary: Interservice communication via message bus for microservices
196
153
  test_files: []
@@ -1,181 +0,0 @@
1
- require 'bunny'
2
-
3
- module Mimi
4
- module Messaging
5
- class Connection
6
- attr_reader :queue_prefix
7
-
8
- # Creates a Connection with given connection params
9
- #
10
- # @param params [Hash] Connection params as accepted by Bunny
11
- # @param params[:queue_prefix] [String] (optional) Use this connection for all communication
12
- # related to queues, having names starting with given
13
- # prefix
14
- #
15
- def initialize(params = {})
16
- @queue_prefix = params[:queue_prefix]
17
- @channel_pool = {}
18
- bunny_params = {
19
- host: params[:mq_host],
20
- port: params[:mq_port],
21
- username: params[:mq_username],
22
- password: params[:mq_password],
23
- vhost: params[:mq_vhost]
24
- }
25
- @connection = Bunny.new(bunny_params)
26
- end
27
-
28
- # Starts the connection, opening actual connection to RabbitMQ
29
- #
30
- def start
31
- @connection.start
32
- end
33
-
34
- # Stops the connection
35
- #
36
- def stop
37
- @connection.close
38
- @channel_pool = {}
39
- end
40
-
41
- def started?
42
- @connection.status == :open
43
- end
44
-
45
- def channel
46
- raise ConnectionError unless started?
47
- @channel_pool[Thread.current.object_id] ||= create_channel
48
- end
49
-
50
- def create_channel(opts = {})
51
- Channel.new(@connection, opts)
52
- end
53
-
54
- def reply_queue
55
- raise ConnectionError unless started?
56
- channel.reply_queue
57
- end
58
-
59
- def post(queue_name, raw_message, params = {})
60
- channel.post(queue_name, raw_message, params)
61
- end
62
-
63
- def get(queue_name, raw_message, params = {})
64
- channel.get(queue_name, raw_message, params)
65
- end
66
-
67
- def broadcast(queue_name, raw_message, params = {})
68
- channel.broadcast(queue_name, raw_message, params)
69
- end
70
-
71
- class Channel
72
- attr_reader :options, :connection
73
-
74
- DEFAULT_OPTIONS = {
75
- concurrency: 1
76
- }
77
- DEFAULT_GET_TIMEOUT = 60 # seconds
78
-
79
- def initialize(connection, opts = {})
80
- @connection = connection
81
- @options = DEFAULT_OPTIONS.merge(opts)
82
- @channel = @connection.create_channel(nil, options[:concurrency])
83
- @mutex = Mutex.new
84
- end
85
-
86
- def create_queue(name, opts = {})
87
- @channel.queue(name, opts)
88
- end
89
-
90
- def reply_queue
91
- @reply_queue ||= create_queue('', exclusive: true)
92
- end
93
-
94
- def ack(tag)
95
- @channel.ack(tag)
96
- end
97
-
98
- def fanout(name)
99
- @channel.fanout(name)
100
- end
101
-
102
- def active?
103
- @channel && @channel.active
104
- end
105
-
106
- # Sends a raw RabbitMQ message to a given direct exchange
107
- #
108
- # @param queue_name [String] Queue name to send the message to
109
- # @param raw_message [String]
110
- # @param params [Hash] Message params (metadata)
111
- #
112
- def post(queue_name, raw_message, params = {})
113
- x = @channel.default_exchange
114
- params = { routing_key: queue_name }.merge(params.dup)
115
- publish(x, raw_message, params)
116
- end
117
-
118
- # Sends a raw RabbitMQ message to a given direct exchange and listens for response
119
- #
120
- # @param queue_name [String] Queue name to send the message to
121
- # @param raw_message [String]
122
- # @param params [Hash] Message params (metadata)
123
- #
124
- # @param params[:timeout] [Integer] (optional) Timeout in seconds
125
- #
126
- # @return [nil,Array]
127
- #
128
- def get(queue_name, raw_message, params = {})
129
- correlation_id = Time.now.utc.to_f.to_s
130
- params = params.dup.merge(
131
- reply_to: reply_queue.name,
132
- correlation_id: correlation_id
133
- )
134
- post(queue_name, raw_message, params)
135
- response = nil
136
- begin
137
- Timeout.timeout(params[:timeout] || DEFAULT_GET_TIMEOUT) do
138
- loop do
139
- d, m, p = reply_queue.pop
140
- next if d && m.correlation_id != correlation_id
141
- response = [d, m, p] if d
142
- break if response
143
- sleep 0.001 # s
144
- end
145
- end
146
- rescue Timeout::Error
147
- # respond with nil
148
- end
149
- response
150
- end
151
-
152
- # Sends a raw RabbitMQ message to a given fanout exchange
153
- #
154
- # @param fanout_name [String] Fanout exchange name to send the message to
155
- # @param raw_message [String]
156
- # @param params [Hash] Message params (metadata)
157
- #
158
- def broadcast(fanout_name, raw_message, params = {})
159
- x = @channel.fanout(fanout_name)
160
- publish(x, raw_message, params)
161
- end
162
-
163
- private
164
-
165
- def publish(exchange, raw_message, params = {})
166
- # HACK: Connection-level mutex reduces throughoutput, hopefully improves stability (ku)
167
- @mutex.synchronize do
168
- # TODO: may be make publishing an atomic operation using a separate thread? (ku)
169
- exchange.publish(raw_message, params)
170
- end
171
- rescue StandardError => e
172
- # Raising fatal error:
173
- unless Thread.main == Thread.current
174
- Thread.main.raise ConnectionError, "failed to publish message in a child thread: #{e}"
175
- end
176
- raise ConnectionError, "failed to publish message: #{e}"
177
- end
178
- end # class Channel
179
- end # class Connection
180
- end # module Messaging
181
- end # module Mimi