jetstream_bridge 1.6.0 → 1.7.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 +4 -4
- data/.idea/dictionaries/project.xml +1 -0
- data/.idea/jetstream_bridge.iml +6 -1
- data/.rubocop.yml +102 -0
- data/Gemfile.lock +1 -5
- data/README.md +76 -32
- data/jetstream_bridge.gemspec +9 -10
- data/lib/generators/jetstream_bridge/initializer/initializer_generator.rb +16 -0
- data/lib/generators/jetstream_bridge/initializer/templates/jetstream_bridge.rb +24 -0
- data/lib/generators/jetstream_bridge/install/install_generator.rb +19 -0
- data/lib/generators/jetstream_bridge/migrations/migrations_generator.rb +44 -0
- data/lib/generators/jetstream_bridge/migrations/templates/create_jetstream_inbox_events.rb.erb +24 -0
- data/lib/generators/jetstream_bridge/migrations/templates/create_jetstream_outbox_events.rb.erb +21 -0
- data/lib/jetstream_bridge/consumer/consumer.rb +103 -0
- data/lib/jetstream_bridge/{consumer_config.rb → consumer/consumer_config.rb} +3 -3
- data/lib/jetstream_bridge/consumer/inbox/inbox_message.rb +50 -0
- data/lib/jetstream_bridge/consumer/inbox/inbox_processor.rb +51 -0
- data/lib/jetstream_bridge/consumer/inbox/inbox_repository.rb +102 -0
- data/lib/jetstream_bridge/{message_processor.rb → consumer/message_processor.rb} +1 -1
- data/lib/jetstream_bridge/consumer/subscription_manager.rb +91 -0
- data/lib/jetstream_bridge/{connection.rb → core/connection.rb} +1 -1
- data/lib/jetstream_bridge/models/inbox_event.rb +98 -0
- data/lib/jetstream_bridge/models/outbox_event.rb +114 -0
- data/lib/jetstream_bridge/publisher/outbox_repository.rb +70 -0
- data/lib/jetstream_bridge/{publisher.rb → publisher/publisher.rb} +10 -58
- data/lib/jetstream_bridge/railtie.rb +12 -0
- data/lib/jetstream_bridge/tasks/install.rake +10 -0
- data/lib/jetstream_bridge/{overlap_guard.rb → topology/overlap_guard.rb} +6 -4
- data/lib/jetstream_bridge/topology/stream.rb +129 -0
- data/lib/jetstream_bridge/{topology.rb → topology/topology.rb} +2 -2
- data/lib/jetstream_bridge/version.rb +1 -1
- data/lib/jetstream_bridge.rb +35 -23
- metadata +49 -50
- data/lib/jetstream_bridge/consumer.rb +0 -232
- data/lib/jetstream_bridge/dlq.rb +0 -24
- data/lib/jetstream_bridge/inbox_event.rb +0 -46
- data/lib/jetstream_bridge/outbox_event.rb +0 -60
- data/lib/jetstream_bridge/stream.rb +0 -114
- /data/lib/jetstream_bridge/{config.rb → core/config.rb} +0 -0
- /data/lib/jetstream_bridge/{duration.rb → core/duration.rb} +0 -0
- /data/lib/jetstream_bridge/{logging.rb → core/logging.rb} +0 -0
- /data/lib/jetstream_bridge/{model_utils.rb → core/model_utils.rb} +0 -0
- /data/lib/jetstream_bridge/{subject_matcher.rb → topology/subject_matcher.rb} +0 -0
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'securerandom'
|
5
|
-
require_relative 'connection'
|
6
|
-
require_relative 'logging'
|
7
|
-
require_relative 'config'
|
8
|
-
require_relative 'model_utils'
|
5
|
+
require_relative '../core/connection'
|
6
|
+
require_relative '../core/logging'
|
7
|
+
require_relative '../core/config'
|
8
|
+
require_relative '../core/model_utils'
|
9
9
|
|
10
10
|
module JetstreamBridge
|
11
11
|
# Publishes to "{env}.data.sync.{app}.{dest}".
|
@@ -63,71 +63,23 @@ module JetstreamBridge
|
|
63
63
|
return with_retries { do_publish(subject, envelope) }
|
64
64
|
end
|
65
65
|
|
66
|
-
|
66
|
+
repo = OutboxRepository.new(klass)
|
67
67
|
event_id = envelope['event_id'].to_s
|
68
|
+
record = repo.find_or_build(event_id)
|
68
69
|
|
69
|
-
|
70
|
-
klass,
|
71
|
-
{ event_id: event_id },
|
72
|
-
# Fallback key if app uses a different unique column:
|
73
|
-
{ dedup_key: event_id }
|
74
|
-
)
|
75
|
-
|
76
|
-
# If already sent, do nothing
|
77
|
-
if record.respond_to?(:sent_at) && record.sent_at
|
70
|
+
if repo.already_sent?(record)
|
78
71
|
Logging.info("Outbox already sent event_id=#{event_id}; skipping publish.",
|
79
72
|
tag: 'JetstreamBridge::Publisher')
|
80
73
|
return true
|
81
74
|
end
|
82
75
|
|
83
|
-
|
84
|
-
ModelUtils.assign_known_attrs(record, {
|
85
|
-
event_id: event_id,
|
86
|
-
subject: subject,
|
87
|
-
payload: ModelUtils.json_dump(envelope),
|
88
|
-
headers: ModelUtils.json_dump({ 'Nats-Msg-Id' => event_id }),
|
89
|
-
status: 'publishing',
|
90
|
-
attempts: (record.respond_to?(:attempts) ? (record.attempts || 0) + 1 : nil),
|
91
|
-
last_error: nil,
|
92
|
-
enqueued_at: (record.respond_to?(:enqueued_at) ? (record.enqueued_at || now) : nil),
|
93
|
-
updated_at: (record.respond_to?(:updated_at) ? now : nil)
|
94
|
-
})
|
95
|
-
record.save!
|
76
|
+
repo.persist_pre(record, subject, envelope)
|
96
77
|
|
97
78
|
ok = with_retries { do_publish(subject, envelope) }
|
98
|
-
|
99
|
-
if ok
|
100
|
-
ModelUtils.assign_known_attrs(record, {
|
101
|
-
status: 'sent',
|
102
|
-
sent_at: (record.respond_to?(:sent_at) ? now : nil),
|
103
|
-
updated_at: (record.respond_to?(:updated_at) ? now : nil)
|
104
|
-
})
|
105
|
-
record.save!
|
106
|
-
else
|
107
|
-
ModelUtils.assign_known_attrs(record, {
|
108
|
-
status: 'failed',
|
109
|
-
last_error: 'Publish returned false',
|
110
|
-
updated_at: (record.respond_to?(:updated_at) ? now : nil)
|
111
|
-
})
|
112
|
-
record.save!
|
113
|
-
end
|
114
|
-
|
79
|
+
ok ? repo.persist_success(record) : repo.persist_failure(record, 'Publish returned false')
|
115
80
|
ok
|
116
81
|
rescue => e
|
117
|
-
|
118
|
-
begin
|
119
|
-
if record
|
120
|
-
ModelUtils.assign_known_attrs(record, {
|
121
|
-
status: 'failed',
|
122
|
-
last_error: "#{e.class}: #{e.message}",
|
123
|
-
updated_at: (record.respond_to?(:updated_at) ? Time.now.utc : nil)
|
124
|
-
})
|
125
|
-
record.save!
|
126
|
-
end
|
127
|
-
rescue => e2
|
128
|
-
Logging.warn("Failed to persist outbox failure: #{e2.class}: #{e2.message}",
|
129
|
-
tag: 'JetstreamBridge::Publisher')
|
130
|
-
end
|
82
|
+
repo.persist_exception(record, e) if defined?(repo) && defined?(record)
|
131
83
|
log_error(false, e)
|
132
84
|
end
|
133
85
|
# ---- /Outbox path ----
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :jetstream_bridge do
|
4
|
+
desc 'Install JetstreamBridge (initializer + migrations)'
|
5
|
+
task install: :environment do
|
6
|
+
puts '[jetstream_bridge] Generating initializer and migrations...'
|
7
|
+
Rails::Generators.invoke('jetstream_bridge:install', [], behavior: :invoke, destination_root: Rails.root.to_s)
|
8
|
+
puts '[jetstream_bridge] Done.'
|
9
|
+
end
|
10
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require_relative 'subject_matcher'
|
5
|
-
require_relative 'logging'
|
5
|
+
require_relative '../core/logging'
|
6
6
|
|
7
7
|
module JetstreamBridge
|
8
8
|
# Checks for overlapping subjects.
|
@@ -12,6 +12,7 @@ module JetstreamBridge
|
|
12
12
|
def check!(jts, target_name, new_subjects)
|
13
13
|
conflicts = overlaps(jts, target_name, new_subjects)
|
14
14
|
return if conflicts.empty?
|
15
|
+
|
15
16
|
raise conflict_message(target_name, conflicts)
|
16
17
|
end
|
17
18
|
|
@@ -22,13 +23,13 @@ module JetstreamBridge
|
|
22
23
|
streams = list_streams_with_subjects(jts)
|
23
24
|
others = streams.reject { |s| s[:name] == target_name }
|
24
25
|
|
25
|
-
others.
|
26
|
+
others.filter_map do |s|
|
26
27
|
pairs = desired.flat_map do |n|
|
27
28
|
Array(s[:subjects]).map(&:to_s).select { |e| SubjectMatcher.overlap?(n, e) }
|
28
29
|
.map { |e| [n, e] }
|
29
30
|
end
|
30
31
|
{ name: s[:name], pairs: pairs } unless pairs.empty?
|
31
|
-
end
|
32
|
+
end
|
32
33
|
end
|
33
34
|
|
34
35
|
# Returns [allowed, blocked] given desired subjects.
|
@@ -56,9 +57,10 @@ module JetstreamBridge
|
|
56
57
|
offset = 0
|
57
58
|
loop do
|
58
59
|
resp = js_api_request(jts, '$JS.API.STREAM.NAMES', { offset: offset })
|
59
|
-
batch = Array(resp['streams']).
|
60
|
+
batch = Array(resp['streams']).filter_map { |h| h['name'] }
|
60
61
|
names.concat(batch)
|
61
62
|
break if names.size >= resp['total'].to_i || batch.empty?
|
63
|
+
|
62
64
|
offset = names.size
|
63
65
|
end
|
64
66
|
names
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../core/logging'
|
4
|
+
require_relative 'overlap_guard'
|
5
|
+
require_relative 'subject_matcher'
|
6
|
+
|
7
|
+
module JetstreamBridge
|
8
|
+
# Ensures a stream exists and adds only subjects that are not already covered.
|
9
|
+
class Stream
|
10
|
+
class << self
|
11
|
+
def ensure!(jts, name, subjects)
|
12
|
+
desired = normalize_subjects(subjects)
|
13
|
+
raise ArgumentError, 'subjects must not be empty' if desired.empty?
|
14
|
+
|
15
|
+
attempts = 0
|
16
|
+
begin
|
17
|
+
info = safe_stream_info(jts, name)
|
18
|
+
info ? ensure_update(jts, name, info, desired) : ensure_create(jts, name, desired)
|
19
|
+
rescue NATS::JetStream::Error => e
|
20
|
+
if overlap_error?(e) && (attempts += 1) <= 1
|
21
|
+
Logging.warn("Overlap race while ensuring #{name}; retrying once...", tag: 'JetstreamBridge::Stream')
|
22
|
+
sleep(0.05)
|
23
|
+
retry
|
24
|
+
elsif overlap_error?(e)
|
25
|
+
Logging.warn(
|
26
|
+
"Overlap persists ensuring #{name}; leaving unchanged. err=#{e.message.inspect}",
|
27
|
+
tag: 'JetstreamBridge::Stream')
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
raise
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# ---------- Update existing stream ----------
|
38
|
+
|
39
|
+
def ensure_update(jts, name, info, desired)
|
40
|
+
existing = normalize_subjects(info.config.subjects || [])
|
41
|
+
to_add = missing_subjects(existing, desired)
|
42
|
+
return log_already_covered(name) if to_add.empty?
|
43
|
+
|
44
|
+
allowed, blocked = OverlapGuard.partition_allowed(jts, name, to_add)
|
45
|
+
return log_all_blocked(name, blocked) if allowed.empty?
|
46
|
+
|
47
|
+
target = (existing + allowed).uniq
|
48
|
+
OverlapGuard.check!(jts, name, target)
|
49
|
+
jts.update_stream(name: name, subjects: target)
|
50
|
+
log_updated(name, allowed, blocked)
|
51
|
+
end
|
52
|
+
|
53
|
+
# ---------- Create new stream ----------
|
54
|
+
|
55
|
+
def ensure_create(jts, name, desired)
|
56
|
+
allowed, blocked = OverlapGuard.partition_allowed(jts, name, desired)
|
57
|
+
return log_not_created(name, blocked) if allowed.empty?
|
58
|
+
|
59
|
+
jts.add_stream(name: name, subjects: allowed, retention: 'interest', storage: 'file')
|
60
|
+
log_created(name, allowed, blocked)
|
61
|
+
end
|
62
|
+
|
63
|
+
# ---------- Helpers ----------
|
64
|
+
|
65
|
+
def safe_stream_info(jts, name)
|
66
|
+
jts.stream_info(name)
|
67
|
+
rescue NATS::JetStream::Error => e
|
68
|
+
return nil if stream_not_found?(e)
|
69
|
+
raise
|
70
|
+
end
|
71
|
+
|
72
|
+
def missing_subjects(existing, desired)
|
73
|
+
desired.reject { |d| SubjectMatcher.covered?(existing, d) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def normalize_subjects(list)
|
77
|
+
Array(list).flatten.compact.map!(&:to_s).reject(&:empty?).uniq
|
78
|
+
end
|
79
|
+
|
80
|
+
def stream_not_found?(error)
|
81
|
+
msg = error.message.to_s
|
82
|
+
msg =~ /stream\s+not\s+found/i || msg =~ /\b404\b/
|
83
|
+
end
|
84
|
+
|
85
|
+
def overlap_error?(error)
|
86
|
+
msg = error.message.to_s
|
87
|
+
msg =~ /subjects?\s+overlap/i || msg =~ /\berr_code=10065\b/ || msg =~ /\bstatus_code=400\b/
|
88
|
+
end
|
89
|
+
|
90
|
+
# ---------- Logging wrappers ----------
|
91
|
+
|
92
|
+
def log_already_covered(name)
|
93
|
+
Logging.info("Stream #{name} exists; subjects already covered.", tag: 'JetstreamBridge::Stream')
|
94
|
+
end
|
95
|
+
|
96
|
+
def log_all_blocked(name, blocked)
|
97
|
+
if blocked.any?
|
98
|
+
Logging.warn(
|
99
|
+
"Stream #{name}: all missing subjects are owned by other streams; leaving unchanged. " \
|
100
|
+
"blocked=#{blocked.inspect}",
|
101
|
+
tag: 'JetstreamBridge::Stream'
|
102
|
+
)
|
103
|
+
else
|
104
|
+
Logging.info("Stream #{name} exists; nothing to add.", tag: 'JetstreamBridge::Stream')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def log_updated(name, added, blocked)
|
109
|
+
msg = "Updated stream #{name}; added subjects=#{added.inspect}"
|
110
|
+
msg += " (skipped overlapped=#{blocked.inspect})" if blocked.any?
|
111
|
+
Logging.info(msg, tag: 'JetstreamBridge::Stream')
|
112
|
+
end
|
113
|
+
|
114
|
+
def log_not_created(name, blocked)
|
115
|
+
Logging.warn(
|
116
|
+
"Not creating stream #{name}: all desired subjects are owned by other streams. " \
|
117
|
+
"blocked=#{blocked.inspect}",
|
118
|
+
tag: 'JetstreamBridge::Stream'
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def log_created(name, allowed, blocked)
|
123
|
+
msg = "Created stream #{name} subjects=#{allowed.inspect}"
|
124
|
+
msg += " (skipped overlapped=#{blocked.inspect})" if blocked.any?
|
125
|
+
Logging.info(msg, tag: 'JetstreamBridge::Stream')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/jetstream_bridge.rb
CHANGED
@@ -1,48 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'jetstream_bridge/version'
|
4
|
-
require_relative 'jetstream_bridge/config'
|
5
|
-
require_relative 'jetstream_bridge/duration'
|
6
|
-
require_relative 'jetstream_bridge/logging'
|
7
|
-
require_relative 'jetstream_bridge/connection'
|
8
|
-
require_relative 'jetstream_bridge/publisher'
|
9
|
-
require_relative 'jetstream_bridge/consumer'
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
require_relative 'jetstream_bridge/core/config'
|
5
|
+
require_relative 'jetstream_bridge/core/duration'
|
6
|
+
require_relative 'jetstream_bridge/core/logging'
|
7
|
+
require_relative 'jetstream_bridge/core/connection'
|
8
|
+
require_relative 'jetstream_bridge/publisher/publisher'
|
9
|
+
require_relative 'jetstream_bridge/consumer/consumer'
|
10
|
+
|
11
|
+
# If you have a Railtie for tasks/eager-loading
|
12
|
+
require_relative 'jetstream_bridge/railtie' if defined?(Rails::Railtie)
|
13
|
+
|
14
|
+
# Load gem-provided models from lib/
|
15
|
+
require_relative 'jetstream_bridge/models/outbox_event'
|
16
|
+
require_relative 'jetstream_bridge/models/inbox_event'
|
17
|
+
|
18
18
|
|
19
|
+
# JetstreamBridge main module.
|
20
|
+
module JetstreamBridge
|
19
21
|
class << self
|
20
|
-
# Access the global configuration.
|
21
|
-
# @return [JetstreamBridge::Config]
|
22
22
|
def config
|
23
23
|
@config ||= Config.new
|
24
24
|
end
|
25
25
|
|
26
|
-
# Configure via hash and/or block.
|
27
|
-
# @param overrides [Hash] optional config key/value pairs
|
28
|
-
# @yieldparam [JetstreamBridge::Config] config
|
29
|
-
# @return [JetstreamBridge::Config]
|
30
26
|
def configure(overrides = {})
|
31
27
|
cfg = config
|
32
|
-
overrides.each { |k, v| assign!(cfg, k, v) }
|
28
|
+
overrides.each { |k, v| assign!(cfg, k, v) } unless overrides.nil? || overrides.empty?
|
33
29
|
yield(cfg) if block_given?
|
34
30
|
cfg
|
35
31
|
end
|
36
32
|
|
37
|
-
# Reset memoized config (useful in tests).
|
38
33
|
def reset!
|
39
34
|
@config = nil
|
40
35
|
end
|
41
36
|
|
37
|
+
def use_outbox?
|
38
|
+
config.use_outbox
|
39
|
+
end
|
40
|
+
|
41
|
+
def use_inbox?
|
42
|
+
config.use_inbox
|
43
|
+
end
|
44
|
+
|
45
|
+
def use_dlq?
|
46
|
+
config.use_dlq
|
47
|
+
end
|
48
|
+
|
49
|
+
def ensure_topology!
|
50
|
+
Connection.connect!
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
42
54
|
private
|
43
55
|
|
44
56
|
def assign!(cfg, key, val)
|
45
|
-
setter = "#{key}="
|
57
|
+
setter = :"#{key}="
|
46
58
|
raise ArgumentError, "Unknown configuration option: #{key}" unless cfg.respond_to?(setter)
|
47
59
|
|
48
60
|
cfg.public_send(setter, val)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jetstream_bridge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Attara
|
@@ -67,75 +67,61 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '6.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: bundler-audit
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 0.9.1
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 0.9.1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '13.0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '1.66'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '1.66'
|
96
|
+
version: '13.0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
98
|
+
name: rspec
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
|
-
- - "
|
101
|
+
- - ">="
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
103
|
+
version: '3.12'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
107
|
requirements:
|
122
|
-
- - "
|
108
|
+
- - ">="
|
123
109
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
110
|
+
version: '3.12'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
|
-
name: rubocop
|
112
|
+
name: rubocop
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
128
114
|
requirements:
|
129
115
|
- - "~>"
|
130
116
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
117
|
+
version: '1.66'
|
132
118
|
type: :development
|
133
119
|
prerelease: false
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
135
121
|
requirements:
|
136
122
|
- - "~>"
|
137
123
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
124
|
+
version: '1.66'
|
139
125
|
- !ruby/object:Gem::Dependency
|
140
126
|
name: rubocop-packaging
|
141
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,19 +137,19 @@ dependencies:
|
|
151
137
|
- !ruby/object:Gem::Version
|
152
138
|
version: '0.5'
|
153
139
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
140
|
+
name: rubocop-performance
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
156
142
|
requirements:
|
157
|
-
- - "
|
143
|
+
- - "~>"
|
158
144
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
145
|
+
version: '1.21'
|
160
146
|
type: :development
|
161
147
|
prerelease: false
|
162
148
|
version_requirements: !ruby/object:Gem::Requirement
|
163
149
|
requirements:
|
164
|
-
- - "
|
150
|
+
- - "~>"
|
165
151
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
152
|
+
version: '1.21'
|
167
153
|
description: |-
|
168
154
|
Publisher/Consumer utilities for NATS JetStream with environment-scoped subjects,
|
169
155
|
overlap guards, DLQ routing, retries/backoff, and optional Inbox/Outbox patterns.
|
@@ -182,28 +168,41 @@ files:
|
|
182
168
|
- ".idea/misc.xml"
|
183
169
|
- ".idea/modules.xml"
|
184
170
|
- ".idea/vcs.xml"
|
171
|
+
- ".rubocop.yml"
|
185
172
|
- Gemfile
|
186
173
|
- Gemfile.lock
|
187
174
|
- LICENSE
|
188
175
|
- README.md
|
189
176
|
- jetstream_bridge.gemspec
|
177
|
+
- lib/generators/jetstream_bridge/initializer/initializer_generator.rb
|
178
|
+
- lib/generators/jetstream_bridge/initializer/templates/jetstream_bridge.rb
|
179
|
+
- lib/generators/jetstream_bridge/install/install_generator.rb
|
180
|
+
- lib/generators/jetstream_bridge/migrations/migrations_generator.rb
|
181
|
+
- lib/generators/jetstream_bridge/migrations/templates/create_jetstream_inbox_events.rb.erb
|
182
|
+
- lib/generators/jetstream_bridge/migrations/templates/create_jetstream_outbox_events.rb.erb
|
190
183
|
- lib/jetstream_bridge.rb
|
191
|
-
- lib/jetstream_bridge/
|
192
|
-
- lib/jetstream_bridge/
|
193
|
-
- lib/jetstream_bridge/consumer.rb
|
194
|
-
- lib/jetstream_bridge/
|
195
|
-
- lib/jetstream_bridge/
|
196
|
-
- lib/jetstream_bridge/
|
197
|
-
- lib/jetstream_bridge/
|
198
|
-
- lib/jetstream_bridge/
|
199
|
-
- lib/jetstream_bridge/
|
200
|
-
- lib/jetstream_bridge/
|
201
|
-
- lib/jetstream_bridge/
|
202
|
-
- lib/jetstream_bridge/
|
203
|
-
- lib/jetstream_bridge/
|
204
|
-
- lib/jetstream_bridge/
|
205
|
-
- lib/jetstream_bridge/
|
206
|
-
- lib/jetstream_bridge/
|
184
|
+
- lib/jetstream_bridge/consumer/consumer.rb
|
185
|
+
- lib/jetstream_bridge/consumer/consumer_config.rb
|
186
|
+
- lib/jetstream_bridge/consumer/inbox/inbox_message.rb
|
187
|
+
- lib/jetstream_bridge/consumer/inbox/inbox_processor.rb
|
188
|
+
- lib/jetstream_bridge/consumer/inbox/inbox_repository.rb
|
189
|
+
- lib/jetstream_bridge/consumer/message_processor.rb
|
190
|
+
- lib/jetstream_bridge/consumer/subscription_manager.rb
|
191
|
+
- lib/jetstream_bridge/core/config.rb
|
192
|
+
- lib/jetstream_bridge/core/connection.rb
|
193
|
+
- lib/jetstream_bridge/core/duration.rb
|
194
|
+
- lib/jetstream_bridge/core/logging.rb
|
195
|
+
- lib/jetstream_bridge/core/model_utils.rb
|
196
|
+
- lib/jetstream_bridge/models/inbox_event.rb
|
197
|
+
- lib/jetstream_bridge/models/outbox_event.rb
|
198
|
+
- lib/jetstream_bridge/publisher/outbox_repository.rb
|
199
|
+
- lib/jetstream_bridge/publisher/publisher.rb
|
200
|
+
- lib/jetstream_bridge/railtie.rb
|
201
|
+
- lib/jetstream_bridge/tasks/install.rake
|
202
|
+
- lib/jetstream_bridge/topology/overlap_guard.rb
|
203
|
+
- lib/jetstream_bridge/topology/stream.rb
|
204
|
+
- lib/jetstream_bridge/topology/subject_matcher.rb
|
205
|
+
- lib/jetstream_bridge/topology/topology.rb
|
207
206
|
- lib/jetstream_bridge/version.rb
|
208
207
|
homepage: https://github.com/attaradev/jetstream_bridge
|
209
208
|
licenses:
|