nats_wave 1.1.8 → 1.1.10
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/Gemfile.lock +1 -1
- data/lib/nats_wave/active_record_extension.rb +93 -0
- data/lib/nats_wave/adapters/active_record.rb +207 -0
- data/lib/nats_wave/adapters/datadog_metrics.rb +1 -1
- data/lib/nats_wave/client.rb +411 -154
- data/lib/nats_wave/concerns/mappable.rb +481 -117
- data/lib/nats_wave/configuration.rb +1 -1
- data/lib/nats_wave/database_connector.rb +51 -0
- data/lib/nats_wave/publisher.rb +142 -39
- data/lib/nats_wave/railtie.rb +134 -1
- data/lib/nats_wave/subscriber.rb +391 -1
- data/lib/nats_wave/version.rb +1 -1
- data/lib/nats_wave.rb +114 -8
- metadata +3 -3
- data/lib/nats_wave/concerns/publishable.rb +0 -216
@@ -1,216 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module NatsWave
|
4
|
-
module ActiveRecordExtension
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
def nats_publishable(options = {})
|
9
|
-
include NatsWave::NatsPublishable
|
10
|
-
class_attribute :nats_publishing_options
|
11
|
-
self.nats_publishing_options = {
|
12
|
-
enabled: true,
|
13
|
-
actions: %i[create update
|
14
|
-
destroy],
|
15
|
-
skip_attributes: [],
|
16
|
-
include_associations: [],
|
17
|
-
async: true
|
18
|
-
}.merge(options)
|
19
|
-
|
20
|
-
# Register this model for publishing
|
21
|
-
NatsWave.configuration&.add_publication(name,
|
22
|
-
nats_publishing_options[:actions])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
module NatsPublishable
|
28
|
-
extend ActiveSupport::Concern
|
29
|
-
|
30
|
-
included do
|
31
|
-
after_commit :publish_to_nats_on_create, on: :create, if: :should_publish_create?
|
32
|
-
after_commit :publish_to_nats_on_update, on: :update,
|
33
|
-
if: :should_publish_update?
|
34
|
-
after_commit :publish_to_nats_on_destroy, on: :destroy,
|
35
|
-
if: :should_publish_destroy?
|
36
|
-
end
|
37
|
-
|
38
|
-
class_methods do
|
39
|
-
def nats_wave_enabled?
|
40
|
-
nats_publishing_options[:enabled]
|
41
|
-
end
|
42
|
-
|
43
|
-
def nats_wave_actions
|
44
|
-
nats_publishing_options[:actions]
|
45
|
-
end
|
46
|
-
|
47
|
-
def nats_wave_skip_attributes
|
48
|
-
nats_publishing_options[:skip_attributes]
|
49
|
-
end
|
50
|
-
|
51
|
-
def nats_wave_unique_attributes
|
52
|
-
# Override this method in your models to define unique attributes for syncing
|
53
|
-
%i[email slug code external_icn].select do |attr|
|
54
|
-
column_names.include?(attr.to_s)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def nats_wave_skip_sync_attributes
|
59
|
-
# Override this method to define attributes that shouldn't be synced from other instances
|
60
|
-
%w[created_at updated_at]
|
61
|
-
end
|
62
|
-
|
63
|
-
def nats_wave_attribute_transformations
|
64
|
-
# Override this method to define custom transformations
|
65
|
-
{}
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def should_publish_create?
|
72
|
-
should_publish_action?(:create)
|
73
|
-
end
|
74
|
-
|
75
|
-
def should_publish_update?
|
76
|
-
should_publish_action?(:update) && has_significant_changes?
|
77
|
-
end
|
78
|
-
|
79
|
-
def should_publish_destroy?
|
80
|
-
should_publish_action?(:destroy)
|
81
|
-
end
|
82
|
-
|
83
|
-
def should_publish_action?(action)
|
84
|
-
return false unless self.class.nats_wave_enabled?
|
85
|
-
return false unless self.class.nats_wave_actions.include?(action)
|
86
|
-
return false if Thread.current[:skip_nats_wave_publishing]
|
87
|
-
return false if @skip_nats_wave_publishing
|
88
|
-
|
89
|
-
# Check conditional options
|
90
|
-
return false if nats_publishing_options[:if] && !instance_eval(&nats_publishing_options[:if])
|
91
|
-
|
92
|
-
return false if nats_publishing_options[:unless] && instance_eval(&nats_publishing_options[:unless])
|
93
|
-
|
94
|
-
true
|
95
|
-
end
|
96
|
-
|
97
|
-
def has_significant_changes?
|
98
|
-
skip_attrs = self.class.nats_wave_skip_attributes.map(&:to_s)
|
99
|
-
significant_changes = previous_changes.except(*skip_attrs, 'updated_at')
|
100
|
-
significant_changes.any?
|
101
|
-
end
|
102
|
-
|
103
|
-
def publish_to_nats_on_create
|
104
|
-
publish_to_nats('create', attributes, build_metadata)
|
105
|
-
end
|
106
|
-
|
107
|
-
def publish_to_nats_on_update
|
108
|
-
publish_to_nats('update', previous_changes, build_metadata)
|
109
|
-
end
|
110
|
-
|
111
|
-
def publish_to_nats_on_destroy
|
112
|
-
publish_to_nats('destroy', attributes, build_metadata)
|
113
|
-
end
|
114
|
-
|
115
|
-
def publish_to_nats(action, _data, metadata)
|
116
|
-
subject = build_nats_subject(action)
|
117
|
-
|
118
|
-
NatsWave.client.publish(
|
119
|
-
subject: subject,
|
120
|
-
model: self.class.name,
|
121
|
-
action: action,
|
122
|
-
data: publishable_attributes,
|
123
|
-
metadata: metadata
|
124
|
-
)
|
125
|
-
rescue StandardError => e
|
126
|
-
NatsWave.logger.error("Failed to publish NATS event: #{e.message}")
|
127
|
-
# Don't raise to avoid breaking the main transaction
|
128
|
-
end
|
129
|
-
|
130
|
-
def build_nats_subject(action)
|
131
|
-
prefix = nats_publishing_options&.dig(:subject_prefix)
|
132
|
-
model_name = self.class.name.underscore
|
133
|
-
|
134
|
-
if prefix
|
135
|
-
"#{prefix}.#{model_name}.#{action}"
|
136
|
-
else
|
137
|
-
"#{model_name}.#{action}"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def publishable_attributes
|
142
|
-
attrs = if nats_publishing_options&.dig(:only)
|
143
|
-
attributes.slice(*nats_publishing_options[:only].map(&:to_s))
|
144
|
-
elsif nats_publishing_options&.dig(:except)
|
145
|
-
attributes.except(*nats_publishing_options[:except].map(&:to_s))
|
146
|
-
else
|
147
|
-
attributes
|
148
|
-
end
|
149
|
-
|
150
|
-
# Add associations if configured
|
151
|
-
attrs.merge!(serialize_associations) if nats_publishing_options[:include_associations].present?
|
152
|
-
|
153
|
-
attrs
|
154
|
-
end
|
155
|
-
|
156
|
-
def serialize_associations
|
157
|
-
associations = {}
|
158
|
-
|
159
|
-
self.class.reflect_on_all_associations.each do |association|
|
160
|
-
unless nats_publishing_options[:include_associations].include?(association.name)
|
161
|
-
next
|
162
|
-
end
|
163
|
-
|
164
|
-
case association.macro
|
165
|
-
when :belongs_to
|
166
|
-
if (related = send(association.name))
|
167
|
-
associations["#{association.name}_id"] =
|
168
|
-
related.id
|
169
|
-
if association.polymorphic?
|
170
|
-
associations["#{association.name}_type"] =
|
171
|
-
related.class.name
|
172
|
-
end
|
173
|
-
end
|
174
|
-
when :has_many, :has_and_belongs_to_many
|
175
|
-
if respond_to?("#{association.name}_ids")
|
176
|
-
associations["#{association.name.to_s.singularize}_ids"] =
|
177
|
-
send("#{association.name}_ids")
|
178
|
-
end
|
179
|
-
when :has_one
|
180
|
-
if (related = send(association.name))
|
181
|
-
associations["#{association.name}_id"] =
|
182
|
-
related.id
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
associations
|
188
|
-
end
|
189
|
-
|
190
|
-
def build_metadata
|
191
|
-
metadata = {
|
192
|
-
model_id: id,
|
193
|
-
model_type: self.class.name,
|
194
|
-
table_name: self.class.table_name,
|
195
|
-
primary_key: self.class.primary_key
|
196
|
-
}
|
197
|
-
|
198
|
-
# Add custom metadata if method exists
|
199
|
-
metadata.merge!(nats_wave_metadata) if respond_to?(:nats_wave_metadata,
|
200
|
-
true)
|
201
|
-
|
202
|
-
# Add configured metadata
|
203
|
-
metadata.merge!(nats_publishing_options[:metadata]) if nats_publishing_options[:metadata]
|
204
|
-
|
205
|
-
metadata
|
206
|
-
end
|
207
|
-
|
208
|
-
def skip_nats_wave_publishing!
|
209
|
-
@skip_nats_wave_publishing = true
|
210
|
-
end
|
211
|
-
|
212
|
-
def enable_nats_wave_publishing!
|
213
|
-
@skip_nats_wave_publishing = false
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|