spectre-rabbitmq 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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/spectre/rabbitmq.rb +272 -0
  3. metadata +75 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff5d268247815c24c9ef18aa240d48880d939103f18219daedd70fe27babc866
4
+ data.tar.gz: 2c41a4cf22e0091c7d15e094c6bd226fa802f879e826fbf0ad675fa806cc0a92
5
+ SHA512:
6
+ metadata.gz: e41362194b709e48652fc34de990258b9019f81b2b69e05c21559fec0998be5c92d6649dd0cfaf1e9f96c8a809f35e940cf1c90b7adb99914a597bc4bbe29c7f
7
+ data.tar.gz: c85e00ecf1670ba4dd90079083ba8c4ec3763873a688e4f2b3ad204a577ca76bc0810fcdf6b8f7096d2cce647728498447f605d35ebd4834395d9a97db7fa0ec
@@ -0,0 +1,272 @@
1
+ require 'spectre'
2
+ require 'spectre/logger'
3
+ require 'ostruct'
4
+ require 'bunny'
5
+
6
+
7
+ module Spectre
8
+ module RabbitMQ
9
+ class ActionParamsBase
10
+ attr_reader :config
11
+
12
+ def initialize config, logger
13
+ @logger = logger
14
+ @config = config.deep_clone
15
+ @config['routing_keys'] = []
16
+ end
17
+
18
+ def exchange name, type: 'topic', durable: false, auto_delete: false
19
+ @config['exchange'] = {
20
+ 'name' => name,
21
+ 'durable' => durable,
22
+ 'type' => type,
23
+ 'auto_delete' => auto_delete,
24
+ }
25
+ end
26
+
27
+ def topic name, durable: false, auto_delete: false
28
+ exchange(name, type: 'topic', durable: durable, auto_delete: auto_delete)
29
+ end
30
+
31
+ def routing_keys *names
32
+ @config['routing_keys'] = names
33
+ end
34
+
35
+ def routing_key name
36
+ @config['routing_keys'] << name
37
+ end
38
+ end
39
+
40
+ class ConsumeActionParams < ActionParamsBase
41
+ def initialize config, logger
42
+ super config, logger
43
+
44
+ @config['queue'] = {
45
+ 'name' => nil,
46
+ 'durable' => false,
47
+ 'auto_delete' => false,
48
+ }
49
+
50
+ @config['messages'] = 1
51
+ end
52
+
53
+ def queue name, durable: false, auto_delete: false, exclusive: false
54
+ @config['queue'] = {
55
+ 'name' => name,
56
+ 'durable' => durable,
57
+ 'auto_delete' => auto_delete,
58
+ 'exclusive' => exclusive,
59
+ }
60
+ end
61
+
62
+ def timeout seconds
63
+ @config['timeout'] = seconds
64
+ end
65
+
66
+ def messages count
67
+ @config['messages'] = count
68
+ end
69
+ end
70
+
71
+ class PublishActionParams < ActionParamsBase
72
+ def payload data
73
+ @config['payload'] = data
74
+ end
75
+
76
+ def correlation_id id
77
+ @config['correlation_id'] = id
78
+ end
79
+
80
+ def reply_to receiver
81
+ @config['reply_to'] = receiver
82
+ end
83
+
84
+ alias :body :payload
85
+ end
86
+
87
+ class RabbitMQAction < Spectre::DslClass
88
+ attr_reader :conn, :action, :threads, :messages
89
+
90
+ def initialize config, logger
91
+ @logger = logger
92
+ @config = config
93
+ @conn = nil
94
+
95
+ @threads = []
96
+ @messages = []
97
+
98
+ @config['ssl'] = false
99
+ end
100
+
101
+ def action name
102
+ raise "invalid action '#{name}'" unless ['publish', 'subscribe'].include? name
103
+
104
+ @config['action'] = name
105
+ end
106
+
107
+ def host hostname
108
+ @config['host'] = hostname
109
+ end
110
+
111
+ def use_ssl!
112
+ @config['ssl'] = true
113
+ end
114
+
115
+ def username user
116
+ @config['username'] = user
117
+ end
118
+
119
+ def password pass
120
+ @config['password'] = pass
121
+ end
122
+
123
+ def virtual_host vhost
124
+ @config['virtual_host'] = vhost
125
+ end
126
+
127
+ def consume &block
128
+ params = ConsumeActionParams.new(@config, @logger)
129
+ params.instance_eval(&block)
130
+
131
+ connect()
132
+
133
+ channel = @conn.create_channel
134
+
135
+ exchange = declare_exchange(channel, params)
136
+
137
+ queue = channel.queue(
138
+ params.config['queue']['name'],
139
+ durable: params.config['queue']['durable'],
140
+ auto_delete: params.config['queue']['auto_delete'],
141
+ exclusive: params.config['queue']['exclusive'],
142
+ )
143
+
144
+ @logger.info("declare queue name=#{queue.name} durable=#{params.config['queue']['durable']} auto_delete=#{params.config['queue']['auto_delete']} exclusive=#{params.config['queue']['exclusive']}")
145
+
146
+ params.config['routing_keys'].each do |routing_key|
147
+ queue.bind(exchange, routing_key: routing_key)
148
+ @logger.info("bind exchange=#{exchange.name} queue=#{queue.name} routing_key=#{routing_key}")
149
+ end
150
+
151
+ consumer_thread = Thread.new do
152
+ message_queue = Queue.new
153
+
154
+ queue.subscribe do |_delivery_info, properties, payload|
155
+ message = OpenStruct.new
156
+ message.payload = payload
157
+ message.correlation_id = properties[:correlation_id]
158
+ message.reply_to = properties[:reply_to]
159
+ message.freeze
160
+
161
+ message_queue << message
162
+ end
163
+
164
+ while @messages.count < params.config['messages']
165
+ message = message_queue.pop
166
+ @logger.info("get queue=#{queue.name}\ncorrelation_id: #{message.correlation_id}\nreply_to: #{message.reply_to}\n#{message.payload}")
167
+ @messages << message
168
+ end
169
+ end
170
+
171
+ @threads << consumer_thread
172
+
173
+ Thread.new do
174
+ sleep(params.config['timeout'] || 10)
175
+ consumer_thread.exit
176
+ end
177
+ end
178
+
179
+ def publish &block
180
+ params = PublishActionParams.new(@config, @logger)
181
+ params.instance_eval(&block)
182
+
183
+ connect()
184
+
185
+ channel = @conn.create_channel
186
+
187
+ exchange = declare_exchange(channel, params)
188
+
189
+ routing_key = params.config['routing_keys'].nil? ? nil : params.config['routing_keys'].first
190
+
191
+ exchange.publish(
192
+ params.config['payload'],
193
+ routing_key: routing_key,
194
+ correlation_id: params.config['correlation_id'],
195
+ reply_to: params.config['reply_to']
196
+ )
197
+
198
+ @logger.info("publish exchange=#{params.config['exchange']['name']} routing_key=#{routing_key} payload=\"#{params.config['payload']}\"")
199
+ end
200
+
201
+ def await!
202
+ @threads.each { |x| x.join }
203
+ end
204
+
205
+ private
206
+
207
+ def connect
208
+ return unless @conn.nil?
209
+
210
+ @logger.info("connect #{@config['username']}:*****@#{@config['host']}#{@config['virtual_host']} ssl=#{@config['ssl']}")
211
+
212
+ @conn = Bunny.new(
213
+ host: @config['host'],
214
+ ssl: @config['ssl'],
215
+ username: @config['username'],
216
+ password: @config['password'],
217
+ virtual_host: @config['virtual_host']
218
+ )
219
+
220
+ @conn.start
221
+ end
222
+
223
+ def declare_exchange(channel, params)
224
+ exchange = Bunny::Exchange.new(
225
+ channel,
226
+ params.config['exchange']['type'].to_s,
227
+ params.config['exchange']['name'],
228
+ durable: params.config['exchange']['durable'],
229
+ auto_delete: params.config['exchange']['auto_delete'],
230
+ )
231
+
232
+ @logger.info("declare exchange name=#{exchange.name} type=#{exchange.type} durable=#{params.config['exchange']['durable']} auto_delete=#{params.config['exchange']['auto_delete']}")
233
+
234
+ exchange
235
+ end
236
+ end
237
+
238
+ class << self
239
+ @@config = {}
240
+
241
+ def rabbitmq name, &block
242
+ if @@config.key? name
243
+ config = @@config[name]
244
+ else
245
+ config = {
246
+ 'host' => name,
247
+ }
248
+ end
249
+
250
+ action = RabbitMQAction.new(config, @@logger)
251
+ action._evaluate(&block) if block_given?
252
+
253
+ # Wait for all consumer threads to be finished
254
+ action.threads.each { |x| x.join }
255
+
256
+ action.conn.close
257
+ end
258
+ end
259
+
260
+ Spectre.register do |config|
261
+ @@logger = Spectre::Logging::ModuleLogger.new(config, 'spectre/rabbitmq')
262
+
263
+ if config.key? 'rabbitmq'
264
+ config['rabbitmq'].each do |name, cfg|
265
+ @@config[name] = cfg
266
+ end
267
+ end
268
+ end
269
+
270
+ Spectre.delegate :rabbitmq, to: self
271
+ end
272
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spectre-rabbitmq
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Christian Neubauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: spectre-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.14.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.14.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bunny
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.20.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.20.3
41
+ description: Adds RabbitMQ functionality to the spectre framework
42
+ email:
43
+ - christian.neubauer@ionos.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/spectre/rabbitmq.rb
49
+ homepage: https://github.com/ionos-spectre/spectre-rabbitmq
50
+ licenses:
51
+ - MIT
52
+ metadata:
53
+ homepage_uri: https://github.com/ionos-spectre/spectre-rabbitmq
54
+ source_code_uri: https://github.com/ionos-spectre/spectre-rabbitmq
55
+ changelog_uri: https://github.com/ionos-spectre/spectre-rabbitmq/blob/master/CHANGELOG.md
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.0.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.3.7
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: RabbitMQ module for spectre
75
+ test_files: []