mimi-messaging 0.1.12 → 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 (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 +428 -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/version.rb +3 -1
  30. data/mimi-messaging.gemspec +25 -23
  31. metadata +34 -78
  32. data/lib/mimi/messaging/connection.rb +0 -182
  33. data/lib/mimi/messaging/listener.rb +0 -72
  34. data/lib/mimi/messaging/message.rb +0 -74
  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 -19
  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,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mimi
2
4
  module Messaging
3
- VERSION = '0.1.12'.freeze
5
+ VERSION = "1.0.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.12
4
+ version: 1.0.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-28 00:00:00.000000000 Z
11
+ date: 2019-10-06 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,40 @@ 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
152
- - 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
124
+ - lib/mimi/messaging/json_serializer.rb
167
125
  - lib/mimi/messaging/version.rb
168
- - lib/tasks/console_ext.rake
169
- - lib/tasks/console_helpers.rb
170
126
  - mimi-messaging.gemspec
171
127
  homepage: https://github.com/kukushkin/mimi-messaging
172
128
  licenses:
@@ -189,8 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
145
  version: '0'
190
146
  requirements: []
191
147
  rubyforge_project:
192
- rubygems_version: 2.6.14.1
148
+ rubygems_version: 2.6.14.4
193
149
  signing_key:
194
150
  specification_version: 4
195
- summary: Communications via RabbitMQ for mimi
151
+ summary: Interservice communication via message bus for microservices
196
152
  test_files: []
@@ -1,182 +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
- logger: Mimi::Messaging.logger
25
- }
26
- @connection = Bunny.new(bunny_params)
27
- end
28
-
29
- # Starts the connection, opening actual connection to RabbitMQ
30
- #
31
- def start
32
- @connection.start
33
- end
34
-
35
- # Stops the connection
36
- #
37
- def stop
38
- @connection.close
39
- @channel_pool = {}
40
- end
41
-
42
- def started?
43
- @connection.status == :open
44
- end
45
-
46
- def channel
47
- raise ConnectionError unless started?
48
- @channel_pool[Thread.current.object_id] ||= create_channel
49
- end
50
-
51
- def create_channel(opts = {})
52
- Channel.new(@connection, opts)
53
- end
54
-
55
- def reply_queue
56
- raise ConnectionError unless started?
57
- channel.reply_queue
58
- end
59
-
60
- def post(queue_name, raw_message, params = {})
61
- channel.post(queue_name, raw_message, params)
62
- end
63
-
64
- def get(queue_name, raw_message, params = {})
65
- channel.get(queue_name, raw_message, params)
66
- end
67
-
68
- def broadcast(queue_name, raw_message, params = {})
69
- channel.broadcast(queue_name, raw_message, params)
70
- end
71
-
72
- class Channel
73
- attr_reader :options, :connection
74
-
75
- DEFAULT_OPTIONS = {
76
- concurrency: 1
77
- }
78
- DEFAULT_GET_TIMEOUT = 60 # seconds
79
-
80
- def initialize(connection, opts = {})
81
- @connection = connection
82
- @options = DEFAULT_OPTIONS.merge(opts)
83
- @channel = @connection.create_channel(nil, options[:concurrency])
84
- @mutex = Mutex.new
85
- end
86
-
87
- def create_queue(name, opts = {})
88
- @channel.queue(name, opts)
89
- end
90
-
91
- def reply_queue
92
- @reply_queue ||= create_queue('', exclusive: true)
93
- end
94
-
95
- def ack(tag)
96
- @channel.ack(tag)
97
- end
98
-
99
- def fanout(name)
100
- @channel.fanout(name)
101
- end
102
-
103
- def active?
104
- @channel && @channel.active
105
- end
106
-
107
- # Sends a raw RabbitMQ message to a given direct exchange
108
- #
109
- # @param queue_name [String] Queue name to send the message to
110
- # @param raw_message [String]
111
- # @param params [Hash] Message params (metadata)
112
- #
113
- def post(queue_name, raw_message, params = {})
114
- x = @channel.default_exchange
115
- params = { routing_key: queue_name }.merge(params.dup)
116
- publish(x, raw_message, params)
117
- end
118
-
119
- # Sends a raw RabbitMQ message to a given direct exchange and listens for response
120
- #
121
- # @param queue_name [String] Queue name to send the message to
122
- # @param raw_message [String]
123
- # @param params [Hash] Message params (metadata)
124
- #
125
- # @param params[:timeout] [Integer] (optional) Timeout in seconds
126
- #
127
- # @return [nil,Array]
128
- #
129
- def get(queue_name, raw_message, params = {})
130
- correlation_id = Time.now.utc.to_f.to_s
131
- params = params.dup.merge(
132
- reply_to: reply_queue.name,
133
- correlation_id: correlation_id
134
- )
135
- post(queue_name, raw_message, params)
136
- response = nil
137
- begin
138
- Timeout.timeout(params[:timeout] || DEFAULT_GET_TIMEOUT) do
139
- loop do
140
- d, m, p = reply_queue.pop
141
- next if d && m.correlation_id != correlation_id
142
- response = [d, m, p] if d
143
- break if response
144
- sleep 0.001 # s
145
- end
146
- end
147
- rescue Timeout::Error
148
- # respond with nil
149
- end
150
- response
151
- end
152
-
153
- # Sends a raw RabbitMQ message to a given fanout exchange
154
- #
155
- # @param fanout_name [String] Fanout exchange name to send the message to
156
- # @param raw_message [String]
157
- # @param params [Hash] Message params (metadata)
158
- #
159
- def broadcast(fanout_name, raw_message, params = {})
160
- x = @channel.fanout(fanout_name)
161
- publish(x, raw_message, params)
162
- end
163
-
164
- private
165
-
166
- def publish(exchange, raw_message, params = {})
167
- # HACK: Connection-level mutex reduces throughoutput, hopefully improves stability (ku)
168
- @mutex.synchronize do
169
- # TODO: may be make publishing an atomic operation using a separate thread? (ku)
170
- exchange.publish(raw_message, params)
171
- end
172
- rescue StandardError => e
173
- # Raising fatal error:
174
- unless Thread.main == Thread.current
175
- Thread.main.raise ConnectionError, "failed to publish message in a child thread: #{e}"
176
- end
177
- raise ConnectionError, "failed to publish message: #{e}"
178
- end
179
- end # class Channel
180
- end # class Connection
181
- end # module Messaging
182
- end # module Mimi