sneakers-queue-migrator 0.1.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +39 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +12 -0
- data/docker-compose.yml +16 -0
- data/lib/sneakers/migrator/version.rb +7 -0
- data/lib/sneakers/migrator.rb +208 -0
- data/sneakers-queue-migrator.gemspec +38 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fc0b131523f71a4bd19d4d5d0275fbe7e47814e55ad51b0d927b2672ed7578cb
|
4
|
+
data.tar.gz: 3ee9adb466b69696575011fd7a4a192cac88f9370226b33566cb07a084a637f8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 663174974230df88b4c71ed747c682c5329347d5c815087fd0c59cfa93d05c2e05d8dd196d1345a05b2c4e787850513fc40e727e5a0a7ba61dd63ed0d63677d1
|
7
|
+
data.tar.gz: b4023d485167c76211c06ba6765c550589fceaae77e1c6ed47d91a22d6d228a31b673168d06429a8fbc2b207e94f8845b06243b13386a71e3dc607403058f724
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.1
|
3
|
+
SuggestExtensions: false
|
4
|
+
|
5
|
+
Style/StringLiterals:
|
6
|
+
EnforcedStyle: double_quotes
|
7
|
+
|
8
|
+
Style/StringLiteralsInInterpolation:
|
9
|
+
EnforcedStyle: double_quotes
|
10
|
+
|
11
|
+
Style/Documentation:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/MultilineBlockChain:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Metrics/BlockLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/ClassLength:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Metrics/CyclomaticComplexity:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/ModuleLength:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Metrics/AbcSize:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Metrics/MethodLength:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Metrics/PerceivedComplexity:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Layout/LineLength:
|
39
|
+
Enabled: false
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in sneakers-queue-migrator.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", ">= 12.0"
|
9
|
+
|
10
|
+
gem "minitest", "~> 5.16"
|
11
|
+
|
12
|
+
gem "rubocop", "~> 1.21"
|
13
|
+
|
14
|
+
gem "sneakers", "~> 2.12"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sneakers-queue-migrator (0.1.0)
|
5
|
+
bunny (~> 2.0)
|
6
|
+
json (~> 2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
amq-protocol (2.3.4)
|
12
|
+
ast (2.4.3)
|
13
|
+
bunny (2.24.0)
|
14
|
+
amq-protocol (~> 2.3)
|
15
|
+
sorted_set (~> 1, >= 1.0.2)
|
16
|
+
concurrent-ruby (1.3.5)
|
17
|
+
json (2.10.2)
|
18
|
+
language_server-protocol (3.17.0.4)
|
19
|
+
lint_roller (1.1.0)
|
20
|
+
minitest (5.16.3)
|
21
|
+
parallel (1.26.3)
|
22
|
+
parser (3.3.7.4)
|
23
|
+
ast (~> 2.4.1)
|
24
|
+
racc
|
25
|
+
prism (1.4.0)
|
26
|
+
racc (1.8.1)
|
27
|
+
rainbow (3.1.1)
|
28
|
+
rake (12.3.3)
|
29
|
+
rbtree (0.4.6)
|
30
|
+
regexp_parser (2.10.0)
|
31
|
+
rubocop (1.75.2)
|
32
|
+
json (~> 2.3)
|
33
|
+
language_server-protocol (~> 3.17.0.2)
|
34
|
+
lint_roller (~> 1.1.0)
|
35
|
+
parallel (~> 1.10)
|
36
|
+
parser (>= 3.3.0.2)
|
37
|
+
rainbow (>= 2.2.2, < 4.0)
|
38
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
39
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
40
|
+
ruby-progressbar (~> 1.7)
|
41
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
42
|
+
rubocop-ast (1.44.0)
|
43
|
+
parser (>= 3.3.7.2)
|
44
|
+
prism (~> 1.4)
|
45
|
+
ruby-progressbar (1.13.0)
|
46
|
+
serverengine (2.1.1)
|
47
|
+
sigdump (~> 0.2.2)
|
48
|
+
set (1.1.2)
|
49
|
+
sigdump (0.2.5)
|
50
|
+
sneakers (2.12.0)
|
51
|
+
bunny (~> 2.14)
|
52
|
+
concurrent-ruby (~> 1.0)
|
53
|
+
rake (~> 12.3)
|
54
|
+
serverengine (~> 2.1.0)
|
55
|
+
thor
|
56
|
+
sorted_set (1.0.3)
|
57
|
+
rbtree
|
58
|
+
set (~> 1.0)
|
59
|
+
thor (1.3.2)
|
60
|
+
unicode-display_width (3.1.4)
|
61
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
62
|
+
unicode-emoji (4.0.4)
|
63
|
+
|
64
|
+
PLATFORMS
|
65
|
+
ruby
|
66
|
+
x86_64-linux
|
67
|
+
|
68
|
+
DEPENDENCIES
|
69
|
+
minitest (~> 5.16)
|
70
|
+
rake (>= 12.0)
|
71
|
+
rubocop (~> 1.21)
|
72
|
+
sneakers (~> 2.12)
|
73
|
+
sneakers-queue-migrator!
|
74
|
+
|
75
|
+
BUNDLED WITH
|
76
|
+
2.6.3
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 TODO: Write your name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Sneakers Queue Migrator
|
2
|
+
|
3
|
+
A Ruby gem to safely migrate RabbitMQ queues when queue arguments change, with dynamic Sneakers subscriber discovery, queue argument comparison, and safe message shoveling.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
- Discovers all Sneakers subscribers dynamically
|
7
|
+
- Compares current and desired queue arguments using the RabbitMQ Management API
|
8
|
+
- Safely migrates messages between queues using Bunny
|
9
|
+
- Exposes a class-based API for integration
|
10
|
+
- Optionally provides a Rake task for Rails apps
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'sneakers-queue-migrator'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle install
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install sneakers-queue-migrator
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
You need the sneakers or kicks gem for this to work
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'sneakers/migrator'
|
33
|
+
|
34
|
+
# Example usage (API subject to change)
|
35
|
+
Sneakers::Migrator.migrate!(
|
36
|
+
amqp_url: 'amqp://user:password@rabbitmq:5672/',
|
37
|
+
amqp_api_url: 'http://user:password@rabbitmq:15672',
|
38
|
+
subscriber_paths: ['app/workers/**/*.rb']
|
39
|
+
)
|
40
|
+
```
|
41
|
+
|
42
|
+
## Development
|
43
|
+
|
44
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
Bug reports and pull requests are welcome!
|
48
|
+
|
49
|
+
## License
|
50
|
+
MIT
|
data/Rakefile
ADDED
data/docker-compose.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
version: '3.8'
|
2
|
+
services:
|
3
|
+
rabbitmq:
|
4
|
+
image: rabbitmq:4.1-management
|
5
|
+
ports:
|
6
|
+
- "5672:5672"
|
7
|
+
- "15672:15672"
|
8
|
+
environment:
|
9
|
+
RABBITMQ_DEFAULT_USER: guest
|
10
|
+
RABBITMQ_DEFAULT_PASS: guest
|
11
|
+
RABBITMQ_DEFAULT_VHOST: test_vhost
|
12
|
+
healthcheck:
|
13
|
+
test: ["CMD", "rabbitmq-diagnostics", "ping"]
|
14
|
+
interval: 5s
|
15
|
+
timeout: 5s
|
16
|
+
retries: 10
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "migrator/version"
|
4
|
+
require "bunny"
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
require "uri"
|
8
|
+
|
9
|
+
module Sneakers
|
10
|
+
# Do not define a module named Queue here to avoid conflict with Sneakers::Queue (which is a class, not a module)
|
11
|
+
module Migrator
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Main migration entrypoint
|
16
|
+
def migrate!(amqp_url:, amqp_api_url:, subscriber_paths: [], logger: nil)
|
17
|
+
logger ||= $stdout
|
18
|
+
# Try to require sneakers or kicks
|
19
|
+
begin
|
20
|
+
require "sneakers"
|
21
|
+
rescue LoadError
|
22
|
+
begin
|
23
|
+
require "kicks"
|
24
|
+
rescue LoadError
|
25
|
+
raise Error, "You must have either the 'sneakers' or 'kicks' gem installed to use subscriber discovery."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# Load all subscribers
|
29
|
+
subscriber_paths.each do |path|
|
30
|
+
Dir[File.join(path, "*.rb")].each { |f| require f }
|
31
|
+
end
|
32
|
+
# Find all worker classes for the loaded framework
|
33
|
+
subscribers = ObjectSpace.each_object(Class).select do |klass|
|
34
|
+
klass.included_modules.include?(::Sneakers::Worker)
|
35
|
+
rescue StandardError
|
36
|
+
false
|
37
|
+
end
|
38
|
+
queues = subscribers.map do |klass|
|
39
|
+
opts = klass.instance_variable_get(:@queue_opts) || {}
|
40
|
+
name = klass.instance_variable_get(:@queue_name) ||
|
41
|
+
(klass.const_defined?(:QUEUE_NAME) ? klass.const_get(:QUEUE_NAME) : nil) ||
|
42
|
+
klass.name.gsub("::", "_").gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
43
|
+
{
|
44
|
+
name: name,
|
45
|
+
exchange: opts[:exchange] || "domain_events",
|
46
|
+
routing_keys: opts[:routing_key] || [],
|
47
|
+
arguments: opts[:arguments] || {},
|
48
|
+
durable: opts.fetch(:durable, true)
|
49
|
+
}.tap { |q| q[:arguments]["x-queue-type"] ||= "classic" }
|
50
|
+
end.uniq { |q| q[:name] }
|
51
|
+
|
52
|
+
conn = Bunny.new(amqp_url)
|
53
|
+
conn.start
|
54
|
+
ch = conn.create_channel
|
55
|
+
|
56
|
+
# Remove unused api_uri and fix variable usage
|
57
|
+
rabbitmq_api_user = URI.parse(amqp_api_url).user
|
58
|
+
rabbitmq_api_pass = URI.parse(amqp_api_url).password
|
59
|
+
all_queues = fetch_all_queues(amqp_api_url, rabbitmq_api_user, rabbitmq_api_pass)
|
60
|
+
|
61
|
+
queues.each do |q|
|
62
|
+
queue_info = all_queues.find { |info| info["name"] == q[:name] }
|
63
|
+
tmp_queue_name = "#{q[:name]}_tmp"
|
64
|
+
if queue_info.nil?
|
65
|
+
logger.puts "Migrator: Queue #{q[:name]} does not exist, creating..."
|
66
|
+
ch.queue(q[:name], durable: q[:durable], arguments: q[:arguments])
|
67
|
+
next
|
68
|
+
end
|
69
|
+
current_args = (queue_info["arguments"] || {}).transform_keys(&:to_s)
|
70
|
+
desired_args = (q[:arguments] || {}).transform_keys(&:to_s)
|
71
|
+
logger.puts "Migrator: Checking queue: #{q[:name]}"
|
72
|
+
logger.puts "Migrator: Current args: #{current_args.inspect}"
|
73
|
+
logger.puts "Migrator: Desired args: #{desired_args.inspect}"
|
74
|
+
if queue_args_match?({ arguments: current_args }, desired_args)
|
75
|
+
logger.puts "Migrator: Queue #{q[:name]} arguments match, nothing to do."
|
76
|
+
next
|
77
|
+
end
|
78
|
+
logger.puts "Migrator: Queue #{q[:name]} arguments differ, migrating..."
|
79
|
+
|
80
|
+
# --- Fetch and store bindings (exchange/routing_key pairs) ---
|
81
|
+
bindings = fetch_queue_bindings(amqp_api_url, rabbitmq_api_user, rabbitmq_api_pass, queue_info)
|
82
|
+
logger.puts "Migrator: Found bindings: #{bindings.inspect}"
|
83
|
+
|
84
|
+
ch.queue(tmp_queue_name, durable: queue_info["durable"], arguments: desired_args)
|
85
|
+
Array(q[:routing_keys]).each do |rk|
|
86
|
+
next if rk.nil? || rk.empty?
|
87
|
+
|
88
|
+
# bind the tmp queue first so new messages go somewhere
|
89
|
+
ch.queue(tmp_queue_name).bind(q[:exchange], routing_key: rk)
|
90
|
+
# unbind the original queue from the exchange
|
91
|
+
logger.puts "Migrator: Unbinding queue #{q[:name]} from exchange #{q[:exchange]} with routing key #{rk}"
|
92
|
+
ch.queue(q[:name], passive: true).unbind(q[:exchange], routing_key: rk)
|
93
|
+
end
|
94
|
+
count = 0
|
95
|
+
queue = ch.queue(q[:name], passive: true)
|
96
|
+
loop do
|
97
|
+
delivery_info, headers, payload = queue.pop
|
98
|
+
break unless payload
|
99
|
+
|
100
|
+
logger.puts "Migrator: Moving message to #{tmp_queue_name}: payload=#{payload.inspect}, headers=#{headers.inspect}, delivery_info=#{delivery_info.inspect}"
|
101
|
+
safe_basic_publish(ch, payload, tmp_queue_name, headers)
|
102
|
+
count += 1
|
103
|
+
end
|
104
|
+
logger.puts "Migrator: Moved #{count} messages to #{tmp_queue_name}"
|
105
|
+
ch.queue(q[:name], passive: true).delete
|
106
|
+
|
107
|
+
# create new queue with desired arguments
|
108
|
+
logger.puts "Migrator: Recreating queue #{q[:name]} with new arguments: #{q[:arguments].inspect}"
|
109
|
+
ch.queue(q[:name], durable: q[:durable], arguments: q[:arguments])
|
110
|
+
|
111
|
+
# --- Restore bindings ---
|
112
|
+
bindings.each do |binding|
|
113
|
+
# Only restore if it's a binding from an exchange (not from a queue)
|
114
|
+
next unless binding["source"] && !binding["source"].empty?
|
115
|
+
|
116
|
+
ch.queue(q[:name]).bind(binding["source"], routing_key: binding["routing_key"])
|
117
|
+
logger.puts "Migrator: Restored binding: exchange=#{binding["source"]}, routing_key=#{binding["routing_key"]}"
|
118
|
+
# now drop the tmp queue binding
|
119
|
+
ch.queue(tmp_queue_name).unbind(binding["source"], routing_key: binding["routing_key"])
|
120
|
+
rescue StandardError => e
|
121
|
+
logger.puts "Migrator: Failed to restore binding: #{e.class}: #{e.message}"
|
122
|
+
end
|
123
|
+
|
124
|
+
count = 0
|
125
|
+
tmp_queue = ch.queue(tmp_queue_name, passive: true)
|
126
|
+
loop do
|
127
|
+
delivery_info, headers, payload = tmp_queue.pop
|
128
|
+
break unless payload
|
129
|
+
|
130
|
+
logger.puts "Migrator: Moving message back to #{q[:name]}: payload=#{payload.inspect}, headers=#{headers.inspect}, delivery_info=#{delivery_info.inspect}"
|
131
|
+
safe_basic_publish(ch, payload, q[:name], headers)
|
132
|
+
count += 1
|
133
|
+
end
|
134
|
+
logger.puts "Migrator: Moved #{count} messages to #{q[:name]}"
|
135
|
+
ch.queue(tmp_queue_name, passive: true).delete
|
136
|
+
logger.puts "Migrator: Migration for #{q[:name]} complete."
|
137
|
+
end
|
138
|
+
ch.close
|
139
|
+
conn.close
|
140
|
+
end
|
141
|
+
|
142
|
+
# Fetches all bindings for a queue using the RabbitMQ Management API
|
143
|
+
def fetch_queue_bindings(api_url, user, pass, queue_info)
|
144
|
+
vhost = queue_info["vhost"] || "/"
|
145
|
+
queue_name = queue_info["name"]
|
146
|
+
uri = URI.parse(api_url)
|
147
|
+
scheme = uri.scheme || "http"
|
148
|
+
host = uri.host
|
149
|
+
port = uri.port || 15_672
|
150
|
+
vhost_enc = URI.encode_www_form_component(vhost)
|
151
|
+
queue_enc = URI.encode_www_form_component(queue_name)
|
152
|
+
url = URI.parse("#{scheme}://#{host}:#{port}/api/queues/#{vhost_enc}/#{queue_enc}/bindings")
|
153
|
+
http = Net::HTTP.new(url.hostname, url.port)
|
154
|
+
http.use_ssl = (scheme == "https")
|
155
|
+
req = Net::HTTP::Get.new(url)
|
156
|
+
req.basic_auth(user, pass)
|
157
|
+
res = http.request(req)
|
158
|
+
return [] unless res.is_a?(Net::HTTPSuccess)
|
159
|
+
|
160
|
+
JSON.parse(res.body)
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
def fetch_all_queues(api_url, user, pass)
|
166
|
+
uri = URI.parse(api_url)
|
167
|
+
scheme = uri.scheme || "http"
|
168
|
+
host = uri.host
|
169
|
+
port = uri.port || 15_672
|
170
|
+
url = URI.parse("#{scheme}://#{host}:#{port}/api/queues")
|
171
|
+
http = Net::HTTP.new(url.hostname, url.port)
|
172
|
+
http.use_ssl = (scheme == "https")
|
173
|
+
req = Net::HTTP::Get.new(url)
|
174
|
+
req.basic_auth(user, pass)
|
175
|
+
res = http.request(req)
|
176
|
+
return [] unless res.is_a?(Net::HTTPSuccess)
|
177
|
+
|
178
|
+
JSON.parse(res.body)
|
179
|
+
end
|
180
|
+
|
181
|
+
def queue_args_match?(queue_info, desired_args)
|
182
|
+
(desired_args.to_a - queue_info[:arguments].to_a).empty? &&
|
183
|
+
(queue_info[:arguments].to_a - desired_args.to_a).empty?
|
184
|
+
end
|
185
|
+
|
186
|
+
def safe_basic_publish(channel, payload, queue_name, headers)
|
187
|
+
# Bunny's queue.pop returns [payload, properties, delivery_info]
|
188
|
+
# The payload is always the message body as a string or nil
|
189
|
+
# The properties hash contains all AMQP properties
|
190
|
+
amqp_property_keys = %i[routing_key persistent mandatory timestamp expiration type reply_to content_type content_encoding correlation_id priority message_id user_id app_id]
|
191
|
+
# Normalize headers to a Hash if it's an Array (Bunny can return either)
|
192
|
+
props = case headers
|
193
|
+
when Hash then headers
|
194
|
+
when Array then headers.to_h
|
195
|
+
else {}
|
196
|
+
end
|
197
|
+
sanitized_properties = props.select { |k, _| amqp_property_keys.include?(k.to_sym) }
|
198
|
+
# Always pass the payload as-is (should be a string or nil)
|
199
|
+
queue = channel.queue(queue_name, passive: true)
|
200
|
+
if sanitized_properties.any?
|
201
|
+
queue.publish(payload, sanitized_properties)
|
202
|
+
else
|
203
|
+
queue.publish(payload)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/sneakers/migrator/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sneakers-queue-migrator"
|
7
|
+
spec.version = Sneakers::Migrator::VERSION
|
8
|
+
spec.authors = ["Mike Gane"]
|
9
|
+
spec.email = ["mike.gane@nexusmods.com"]
|
10
|
+
|
11
|
+
spec.summary = "Ruby sneakers queue migrator for RabbitMQ when you need to change queue arguments."
|
12
|
+
spec.description = "A migrator that handles changing RabbitMQ queue arguments for Sneakers subscribers, ensuring smooth transitions without data loss."
|
13
|
+
spec.homepage = "https://gitlab.nexdev.uk/nexus-mods/public/sneakers-queue-migrator"
|
14
|
+
spec.required_ruby_version = ">= 3.1.0"
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(__dir__) do
|
19
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(
|
21
|
+
"bin/",
|
22
|
+
"test/",
|
23
|
+
"spec/",
|
24
|
+
"features/",
|
25
|
+
".git",
|
26
|
+
".circleci",
|
27
|
+
"appveyor"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
spec.bindir = "exe"
|
33
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
34
|
+
spec.require_paths = ["lib"]
|
35
|
+
|
36
|
+
spec.add_dependency "bunny", "~> 2.0"
|
37
|
+
spec.add_dependency "json", "~> 2.0"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sneakers-queue-migrator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Gane
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-07-03 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: bunny
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '2.0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: json
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.0'
|
40
|
+
description: A migrator that handles changing RabbitMQ queue arguments for Sneakers
|
41
|
+
subscribers, ensuring smooth transitions without data loss.
|
42
|
+
email:
|
43
|
+
- mike.gane@nexusmods.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".rubocop.yml"
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- docker-compose.yml
|
55
|
+
- lib/sneakers/migrator.rb
|
56
|
+
- lib/sneakers/migrator/version.rb
|
57
|
+
- sneakers-queue-migrator.gemspec
|
58
|
+
homepage: https://gitlab.nexdev.uk/nexus-mods/public/sneakers-queue-migrator
|
59
|
+
licenses: []
|
60
|
+
metadata: {}
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.1.0
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.6.3
|
76
|
+
specification_version: 4
|
77
|
+
summary: Ruby sneakers queue migrator for RabbitMQ when you need to change queue arguments.
|
78
|
+
test_files: []
|