nats_wave 1.1.7 → 1.1.9

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.
@@ -18,7 +18,7 @@ module NatsWave
18
18
  def initialize(options = {})
19
19
  @nats_url = ENV['NATS_URL'] || "nats://localhost:4222"
20
20
  @service_name = ENV['NATS_SERVICE_NAME'] || "purplewave"
21
- @version = ENV['NATS_SERVICE_VERSION'] || "1.1.7"
21
+ @version = ENV['NATS_SERVICE_VERSION'] || "1.1.9"
22
22
  @instance_id = ENV['NATS_INSTANCE_ID'] || Socket.gethostname
23
23
  @database_url = ENV['NATS_DATABASE_URL'] || nil
24
24
  @connection_pool_size = (ENV['NATS_CONNECTION_POOL_SIZE'] || 10).to_i
@@ -1,3 +1,54 @@
1
+ # # frozen_string_literal: true
2
+ #
3
+ # module NatsWave
4
+ # class DatabaseConnector
5
+ # def initialize(config)
6
+ # @config = config
7
+ # @adapter = determine_adapter
8
+ # end
9
+ #
10
+ # def apply_change(model:, action:, data:, metadata:)
11
+ # case action.to_s.downcase
12
+ # when 'create'
13
+ # create_record(model, data, metadata)
14
+ # when 'update'
15
+ # update_record(model, data, metadata)
16
+ # when 'delete', 'destroy'
17
+ # delete_record(model, data, metadata)
18
+ # else
19
+ # NatsWave.logger.warn("Unknown action: #{action}")
20
+ # end
21
+ # rescue StandardError => e
22
+ # NatsWave.logger.error("Database operation failed: #{e.message}")
23
+ # raise DatabaseError, "Database operation failed: #{e.message}"
24
+ # end
25
+ #
26
+ # def connected?
27
+ # @adapter.connected?
28
+ # end
29
+ #
30
+ # private
31
+ #
32
+ # def determine_adapter
33
+ # raise ConfigurationError, 'No supported database adapter found' unless defined?(ActiveRecord)
34
+ #
35
+ # Adapters::ActiveRecord.new(@config)
36
+ # end
37
+ #
38
+ # def create_record(model, data, metadata)
39
+ # @adapter.create(model, data, metadata)
40
+ # end
41
+ #
42
+ # def update_record(model, data, metadata)
43
+ # @adapter.update(model, data, metadata)
44
+ # end
45
+ #
46
+ # def delete_record(model, data, metadata)
47
+ # @adapter.delete(model, data, metadata)
48
+ # end
49
+ # end
50
+ # end
51
+
1
52
  # frozen_string_literal: true
2
53
 
3
54
  module NatsWave
@@ -1,47 +1,150 @@
1
- # # frozen_string_literal: true
2
- #
3
- # require 'securerandom'
4
- # require 'json'
5
- #
6
- # # begin
7
- # # require 'nats/client'
8
- # # rescue LoadError
9
- # # # NATS not available - define a mock for testing
10
- # # module NATS
11
- # # def self.connect(url, options = {})
12
- # # NatsClient.new
13
- # # end
14
- # #
15
- # # class NatsClient
16
- # # def connected?
17
- # # false
18
- # # end
1
+ # # # frozen_string_literal: true
19
2
  # #
20
- # # def publish(subject, message)
21
- # # puts "NATS: Publishing to #{subject}: #{message}"
22
- # # end
3
+ # # require 'securerandom'
4
+ # # require 'json'
23
5
  # #
24
- # # def subscribe(subject, options = {})
25
- # # puts "NATS: Subscribing to #{subject}"
26
- # # yield('{"mock": "message"}') if block_given?
27
- # # Subscription.new
28
- # # end
6
+ # # # begin
7
+ # # # require 'nats/client'
8
+ # # # rescue LoadError
9
+ # # # # NATS not available - define a mock for testing
10
+ # # # module NATS
11
+ # # # def self.connect(url, options = {})
12
+ # # # NatsClient.new
13
+ # # # end
14
+ # # #
15
+ # # # class NatsClient
16
+ # # # def connected?
17
+ # # # false
18
+ # # # end
19
+ # # #
20
+ # # # def publish(subject, message)
21
+ # # # puts "NATS: Publishing to #{subject}: #{message}"
22
+ # # # end
23
+ # # #
24
+ # # # def subscribe(subject, options = {})
25
+ # # # puts "NATS: Subscribing to #{subject}"
26
+ # # # yield('{"mock": "message"}') if block_given?
27
+ # # # Subscription.new
28
+ # # # end
29
+ # # #
30
+ # # # def close
31
+ # # # true
32
+ # # # end
33
+ # # # end
34
+ # # #
35
+ # # # class Subscription
36
+ # # # def unsubscribe
37
+ # # # true
38
+ # # # end
39
+ # # # end
40
+ # # # end
41
+ # # # end
29
42
  # #
30
- # # def close
31
- # # true
32
- # # end
33
- # # end
34
- # #
35
- # # class Subscription
36
- # # def unsubscribe
37
- # # true
38
- # # end
39
- # # end
40
- # # end
41
- # # end
42
43
  #
44
+ # # frozen_string_literal: true
45
+ #
46
+ # module NatsWave
47
+ # class Publisher
48
+ # attr_reader :config, :client
49
+ #
50
+ # def initialize(config, client, middleware_stack = [])
51
+ # @config = config
52
+ # @client = client
53
+ # @message_transformer = MessageTransformer.new(config)
54
+ # @dead_letter_queue = DeadLetterQueue.new(config) if config.dead_letter_queue
55
+ # end
56
+ #
57
+ # def publish(subject:, model:, action:, data:, metadata: {})
58
+ # return unless @config.publishing_enabled
59
+ #
60
+ # message = build_message(subject, model, action, data, metadata)
61
+ # full_subject = build_full_subject(subject)
62
+ #
63
+ # if @config.async_publishing && defined?(Concurrent)
64
+ # publish_async(full_subject, message)
65
+ # else
66
+ # publish_sync(full_subject, message)
67
+ # end
68
+ #
69
+ # # Metrics.increment_published_messages(full_subject)
70
+ # rescue => e
71
+ # NatsWave.logger.error("Failed to publish message: #{e.message}")
72
+ # @dead_letter_queue&.store_failed_message(message, e, 0)
73
+ # raise PublishError, "Failed to publish message: #{e.message}"
74
+ # end
75
+ #
76
+ # def publish_batch(events)
77
+ # batch_message = {
78
+ # batch_id: SecureRandom.uuid,
79
+ # events: events,
80
+ # timestamp: Time.current.iso8601,
81
+ # source: build_source_info
82
+ # }
83
+ #
84
+ # subject = "#{@config.default_subject_prefix}.batch"
85
+ #
86
+ # @client.publish(subject, batch_message.to_json)
87
+ #
88
+ # # Metrics.increment_published_messages(subject)
89
+ # NatsWave.logger.info("Published batch with #{events.size} events")
90
+ # end
91
+ #
92
+ # def connected?
93
+ # @client&.connected?
94
+ # end
95
+ #
96
+ # def disconnect
97
+ # # Publisher cleanup if needed
98
+ # end
99
+ #
100
+ # private
101
+ #
102
+ # def build_message(subject, model, action, data, metadata)
103
+ # @message_transformer.build_standard_message(
104
+ # subject: subject,
105
+ # model: model,
106
+ # action: action,
107
+ # data: data,
108
+ # metadata: metadata,
109
+ # source: build_source_info
110
+ # )
111
+ # end
112
+ #
113
+ # def build_source_info
114
+ # {
115
+ # service: @config.service_name,
116
+ # version: @config.version,
117
+ # instance_id: @config.instance_id,
118
+ # environment: defined?(Rails) ? Rails.env : 'test'
119
+ # }
120
+ # end
121
+ #
122
+ # def build_full_subject(subject)
123
+ # if @config.default_subject_prefix && !subject.start_with?(@config.default_subject_prefix)
124
+ # "#{@config.default_subject_prefix}.#{subject}"
125
+ # else
126
+ # subject
127
+ # end
128
+ # end
129
+ #
130
+ # def publish_sync(subject, message)
131
+ # @client.publish(subject, message.to_json)
132
+ # NatsWave.logger.debug("Published sync message to #{subject}")
133
+ # end
134
+ #
135
+ # def publish_async(subject, message)
136
+ # if defined?(Concurrent)
137
+ # Concurrent::Future.execute do
138
+ # @client.publish(subject, message.to_json)
139
+ # NatsWave.logger.debug("Published async message to #{subject}")
140
+ # end
141
+ # else
142
+ # publish_sync(subject, message)
143
+ # end
144
+ # end
145
+ # end
146
+ # end
43
147
 
44
- # frozen_string_literal: true
45
148
 
46
149
  module NatsWave
47
150
  class Publisher
@@ -1,3 +1,116 @@
1
+ # # frozen_string_literal: true
2
+ #
3
+ # require 'rails/railtie'
4
+ #
5
+ # module NatsWave
6
+ # class Railtie < Rails::Railtie
7
+ # config.nats_wave = ActiveSupport::OrderedOptions.new
8
+ #
9
+ # initializer "nats_wave.configure" do |app|
10
+ # # Load configuration from Rails config
11
+ # if app.config.respond_to?(:nats_wave)
12
+ # NatsWave.configure do |config|
13
+ # app.config.nats_wave.each do |key, value|
14
+ # config.send("#{key}=", value) if config.respond_to?("#{key}=")
15
+ # end
16
+ # end
17
+ # end
18
+ #
19
+ # # Load YAML configuration if it exists
20
+ # config_file = Rails.root.join('config', 'nats_wave.yml')
21
+ # if File.exist?(config_file)
22
+ # begin
23
+ # erb_content = ERB.new(File.read(config_file)).result
24
+ # yaml_data = YAML.safe_load(erb_content)
25
+ # yaml_config = yaml_data&.dig(Rails.env.to_s) || yaml_data&.dig(Rails.env) || {}
26
+ #
27
+ # NatsWave.configure do |config|
28
+ # # NATS Configuration
29
+ # config.nats_url = yaml_config.dig('nats', 'url') if yaml_config.dig('nats', 'url')
30
+ # config.connection_pool_size = yaml_config.dig('nats', 'connection_pool_size') if yaml_config.dig('nats', 'connection_pool_size')
31
+ # config.timeout = yaml_config.dig('nats', 'timeout') if yaml_config.dig('nats', 'timeout')
32
+ # config.reconnect_attempts = yaml_config.dig('nats', 'reconnect_attempts') if yaml_config.dig('nats', 'reconnect_attempts')
33
+ #
34
+ # # Service Configuration
35
+ # config.service_name = yaml_config.dig('publishing', 'default_subject_prefix') if yaml_config.dig('publishing', 'default_subject_prefix')
36
+ # config.version = Rails.application.class.parent_name.underscore if defined?(Rails.application.class.parent_name)
37
+ #
38
+ # # Publishing Configuration
39
+ # config.publishing_enabled = yaml_config.dig('publishing', 'enabled') unless yaml_config.dig('publishing', 'enabled').nil?
40
+ # config.default_subject_prefix = yaml_config.dig('publishing', 'default_subject_prefix') if yaml_config.dig('publishing', 'default_subject_prefix')
41
+ # config.batch_size = yaml_config.dig('publishing', 'batch_size') if yaml_config.dig('publishing', 'batch_size')
42
+ # config.async_publishing = yaml_config.dig('publishing', 'async') unless yaml_config.dig('publishing', 'async').nil?
43
+ #
44
+ # # Subscription Configuration
45
+ # config.subscription_enabled = yaml_config.dig('subscription', 'enabled') unless yaml_config.dig('subscription', 'enabled').nil?
46
+ # config.queue_group = yaml_config.dig('subscription', 'queue_group') if yaml_config.dig('subscription', 'queue_group')
47
+ #
48
+ # # Middleware Configuration
49
+ # config.middleware_authentication_enabled = yaml_config.dig('middleware', 'authentication', 'enabled') unless yaml_config.dig('middleware', 'authentication', 'enabled').nil?
50
+ # config.middleware_validation_enabled = yaml_config.dig('middleware', 'validation', 'enabled') unless yaml_config.dig('middleware', 'validation', 'enabled').nil?
51
+ # config.middleware_logging_enabled = yaml_config.dig('middleware', 'logging', 'enabled') unless yaml_config.dig('middleware', 'logging', 'enabled').nil?
52
+ # config.auth_secret_key = yaml_config.dig('middleware', 'authentication', 'secret_key') if yaml_config.dig('middleware', 'authentication', 'secret_key')
53
+ # config.schema_registry_url = yaml_config.dig('middleware', 'validation', 'schema_registry') if yaml_config.dig('middleware', 'validation', 'schema_registry')
54
+ # config.log_level = yaml_config.dig('middleware', 'logging', 'level') if yaml_config.dig('middleware', 'logging', 'level')
55
+ #
56
+ # # Error Handling Configuration
57
+ # config.max_retries = yaml_config.dig('error_handling', 'max_retries') if yaml_config.dig('error_handling', 'max_retries')
58
+ # config.retry_delay = yaml_config.dig('error_handling', 'retry_delay') if yaml_config.dig('error_handling', 'retry_delay')
59
+ # config.dead_letter_queue = yaml_config.dig('error_handling', 'dead_letter_queue') if yaml_config.dig('error_handling', 'dead_letter_queue')
60
+ # end
61
+ # rescue => e
62
+ # Rails.logger.warn "Failed to load NATS Wave YAML configuration: #{e.message}"
63
+ # end
64
+ #
65
+ # # Environment-specific overrides
66
+ # if Rails.env.development?
67
+ # NatsWave.configure do |config|
68
+ # config.log_level = "debug"
69
+ # config.middleware_authentication_enabled = false
70
+ # end
71
+ # elsif Rails.env.test?
72
+ # NatsWave.configure do |config|
73
+ # config.publishing_enabled = false
74
+ # config.subscription_enabled = false
75
+ # end
76
+ # end
77
+ # end
78
+ # end
79
+ #
80
+ # initializer "nats_wave.active_record" do
81
+ # ActiveSupport.on_load(:active_record) do
82
+ # require 'nats_wave/concerns/publishable'
83
+ # include NatsWave::ActiveRecordExtension
84
+ # end
85
+ # end
86
+ #
87
+ # rake_tasks do
88
+ # load "tasks/nats_wave.rake"
89
+ # end
90
+ #
91
+ # generators do
92
+ # require 'generators/nats_wave/install_generator'
93
+ # end
94
+ #
95
+ # # Initialize client on Rails boot
96
+ # initializer "nats_wave.initialize_client", after: :load_config_initializers do
97
+ # Rails.application.config.after_initialize do
98
+ # if NatsWave.configuration&.publishing_enabled || NatsWave.configuration&.subscription_enabled
99
+ # Thread.new do
100
+ # sleep 2 # Give Rails time to fully boot
101
+ # begin
102
+ # NatsWave.client
103
+ # NatsWave.logger.info "NatsWave client initialized"
104
+ # rescue => e
105
+ # NatsWave.logger.error "Failed to initialize NatsWave client: #{e.message}"
106
+ # end
107
+ # end
108
+ # end
109
+ # end
110
+ # end
111
+ # end
112
+ # end
113
+
1
114
  # frozen_string_literal: true
2
115
 
3
116
  require 'rails/railtie'
@@ -77,12 +190,13 @@ module NatsWave
77
190
  end
78
191
  end
79
192
 
80
- initializer "nats_wave.active_record" do
81
- ActiveSupport.on_load(:active_record) do
82
- require 'nats_wave/concerns/publishable'
83
- include NatsWave::ActiveRecordExtension
84
- end
85
- end
193
+ # initializer "nats_wave.active_record" do
194
+ # ActiveSupport.on_load(:active_record) do
195
+ # # Load the ActiveRecord extension (this replaces the old publishable)
196
+ # require 'nats_wave/adapters/active_record'
197
+ # include NatsWave::ActiveRecord
198
+ # end
199
+ # end
86
200
 
87
201
  rake_tasks do
88
202
  load "tasks/nats_wave.rake"
@@ -101,6 +215,12 @@ module NatsWave
101
215
  begin
102
216
  NatsWave.client
103
217
  NatsWave.logger.info "NatsWave client initialized"
218
+
219
+ # Start subscriber if enabled
220
+ if NatsWave.configuration&.subscription_enabled
221
+ NatsWave.client.start_subscriber
222
+ NatsWave.logger.info "NatsWave subscriber started"
223
+ end
104
224
  rescue => e
105
225
  NatsWave.logger.error "Failed to initialize NatsWave client: #{e.message}"
106
226
  end