sidekiq_sqs_processor 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/README.md +315 -0
- data/lib/generators/sidekiq_sqs_processor/install_generator.rb +71 -0
- data/lib/generators/sidekiq_sqs_processor/templates/README.txt +41 -0
- data/lib/generators/sidekiq_sqs_processor/templates/initializer.rb.tt +66 -0
- data/lib/generators/sidekiq_sqs_processor/templates/worker.rb.tt +59 -0
- data/lib/generators/sidekiq_sqs_processor/templates/worker_spec.rb.tt +54 -0
- data/lib/generators/sidekiq_sqs_processor/templates/worker_test.rb.tt +50 -0
- data/lib/generators/sidekiq_sqs_processor/worker_generator.rb +54 -0
- data/lib/sidekiq_sqs_processor/base_worker.rb +82 -0
- data/lib/sidekiq_sqs_processor/configuration.rb +182 -0
- data/lib/sidekiq_sqs_processor/continuous_poller.rb +128 -0
- data/lib/sidekiq_sqs_processor/railtie.rb +102 -0
- data/lib/sidekiq_sqs_processor/version.rb +5 -0
- data/lib/sidekiq_sqs_processor.rb +161 -0
- metadata +158 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
require 'rails/generators/named_base'
|
3
|
+
|
4
|
+
module SidekiqSqsProcessor
|
5
|
+
module Generators
|
6
|
+
class WorkerGenerator < Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
desc "Creates a SidekiqSqsProcessor worker for processing SQS messages."
|
10
|
+
|
11
|
+
class_option :queue, type: :string, default: nil,
|
12
|
+
desc: "The Sidekiq queue for this worker (defaults to sqs_[worker_name])"
|
13
|
+
|
14
|
+
class_option :retry, type: :numeric, default: nil,
|
15
|
+
desc: "Number of retries for this worker (defaults to configuration value)"
|
16
|
+
|
17
|
+
class_option :test, type: :boolean, default: true,
|
18
|
+
desc: "Generate test file for this worker"
|
19
|
+
|
20
|
+
def create_worker_file
|
21
|
+
template "worker.rb.tt", "app/workers/#{file_name}_worker.rb"
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_test_file
|
25
|
+
return unless options[:test]
|
26
|
+
|
27
|
+
if defined?(RSpec) || File.exist?(File.join(destination_root, 'spec'))
|
28
|
+
template "worker_spec.rb.tt", "spec/workers/#{file_name}_worker_spec.rb"
|
29
|
+
elsif File.exist?(File.join(destination_root, 'test'))
|
30
|
+
template "worker_test.rb.tt", "test/workers/#{file_name}_worker_test.rb"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def queue_name
|
37
|
+
options[:queue] || "sqs_#{file_name.underscore}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def retry_option
|
41
|
+
if options[:retry]
|
42
|
+
", retry: #{options[:retry]}"
|
43
|
+
else
|
44
|
+
""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def worker_class_name
|
49
|
+
"#{class_name}Worker"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "sidekiq"
|
2
|
+
|
3
|
+
module SidekiqSqsProcessor
|
4
|
+
class BaseWorker
|
5
|
+
include Sidekiq::Worker
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def process_message_automatically
|
9
|
+
return @process_message_automatically if defined?(@process_message_automatically)
|
10
|
+
@process_message_automatically = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_message_automatically=(value)
|
14
|
+
@process_message_automatically = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def inherited(subclass)
|
18
|
+
super
|
19
|
+
# Copy the process_message_automatically value to subclasses
|
20
|
+
subclass.process_message_automatically = process_message_automatically
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Configure Sidekiq options with defaults
|
25
|
+
sidekiq_options(
|
26
|
+
retry: 2, # Default retry count
|
27
|
+
queue: 'default' # Default queue name
|
28
|
+
)
|
29
|
+
|
30
|
+
def perform(message_data)
|
31
|
+
process_message_data(message_data) if self.class.process_message_automatically
|
32
|
+
end
|
33
|
+
|
34
|
+
# Override this method in your worker
|
35
|
+
def process_message(body)
|
36
|
+
raise NotImplementedError, "You must implement process_message in your worker"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def process_message_data(message_data)
|
42
|
+
begin
|
43
|
+
# Parse and process the message
|
44
|
+
body = JSON.parse(message_data["body"])
|
45
|
+
process_message(body)
|
46
|
+
|
47
|
+
# Delete the message from SQS after successful processing
|
48
|
+
delete_sqs_message(message_data)
|
49
|
+
rescue JSON::ParserError => e
|
50
|
+
handle_error(e, message_data, "Failed to parse message body")
|
51
|
+
rescue Aws::SQS::Errors::ServiceError => e
|
52
|
+
handle_error(e, message_data, "SQS service error")
|
53
|
+
rescue StandardError => e
|
54
|
+
handle_error(e, message_data, "Error processing message")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete_sqs_message(message_data)
|
59
|
+
return unless message_data["queue_url"] && message_data["receipt_handle"]
|
60
|
+
|
61
|
+
SidekiqSqsProcessor.sqs_client.delete_message(
|
62
|
+
queue_url: message_data["queue_url"],
|
63
|
+
receipt_handle: message_data["receipt_handle"]
|
64
|
+
)
|
65
|
+
rescue Aws::SQS::Errors::ServiceError => e
|
66
|
+
handle_error(e, message_data, "Failed to delete message from SQS")
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_error(error, message_data, description)
|
70
|
+
SidekiqSqsProcessor.handle_error(error, {
|
71
|
+
worker: self.class.name,
|
72
|
+
message: message_data,
|
73
|
+
description: description
|
74
|
+
})
|
75
|
+
raise # Re-raise to trigger Sidekiq retry
|
76
|
+
end
|
77
|
+
|
78
|
+
def logger
|
79
|
+
SidekiqSqsProcessor.configuration.logger || Sidekiq.logger
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module SidekiqSqsProcessor
|
2
|
+
class Configuration
|
3
|
+
# AWS credentials
|
4
|
+
attr_accessor :aws_access_key_id, :aws_secret_access_key, :aws_credentials
|
5
|
+
attr_reader :aws_region, :queue_urls, :max_number_of_messages,
|
6
|
+
:visibility_timeout, :wait_time_seconds, :poller_thread_count,
|
7
|
+
:error_handler, :polling_enabled, :polling_type, :poll_on_startup,
|
8
|
+
:polling_frequency, :log_level
|
9
|
+
|
10
|
+
# Worker configuration
|
11
|
+
attr_accessor :worker_retry_count, :worker_queue_name, :logger
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@aws_region = "us-east-1"
|
15
|
+
@queue_urls = []
|
16
|
+
@max_number_of_messages = 10
|
17
|
+
@visibility_timeout = 30
|
18
|
+
@wait_time_seconds = 20
|
19
|
+
@poller_thread_count = 1
|
20
|
+
@worker_retry_count = 25
|
21
|
+
@worker_queue_name = "default"
|
22
|
+
@error_handler = default_error_handler
|
23
|
+
@polling_enabled = true
|
24
|
+
@polling_type = :continuous
|
25
|
+
@poll_on_startup = true
|
26
|
+
@polling_frequency = 60 # seconds
|
27
|
+
@log_level = Logger::INFO
|
28
|
+
end
|
29
|
+
|
30
|
+
def aws_region=(region)
|
31
|
+
@aws_region = region&.strip
|
32
|
+
end
|
33
|
+
|
34
|
+
def queue_urls=(urls)
|
35
|
+
@queue_urls = Array(urls).map(&:strip)
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_queue_url(url)
|
39
|
+
@queue_urls << url.strip
|
40
|
+
@queue_urls.uniq!
|
41
|
+
end
|
42
|
+
|
43
|
+
def max_number_of_messages=(value)
|
44
|
+
@max_number_of_messages = value.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
def visibility_timeout=(value)
|
48
|
+
@visibility_timeout = value.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_time_seconds=(value)
|
52
|
+
@wait_time_seconds = value.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
def poller_thread_count=(value)
|
56
|
+
@poller_thread_count = value.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
def error_handler=(handler)
|
60
|
+
if !handler.respond_to?(:call) && !handler.nil?
|
61
|
+
raise ArgumentError, "Error handler must be callable (respond to #call)"
|
62
|
+
end
|
63
|
+
@error_handler = handler
|
64
|
+
end
|
65
|
+
|
66
|
+
def polling_enabled=(value)
|
67
|
+
@polling_enabled = !!value
|
68
|
+
end
|
69
|
+
|
70
|
+
def polling_type=(value)
|
71
|
+
value = value.to_sym if value.respond_to?(:to_sym)
|
72
|
+
unless [:continuous, :scheduled].include?(value)
|
73
|
+
raise ArgumentError, "polling_type must be :continuous or :scheduled"
|
74
|
+
end
|
75
|
+
@polling_type = value
|
76
|
+
end
|
77
|
+
|
78
|
+
def poll_on_startup=(value)
|
79
|
+
@poll_on_startup = !!value
|
80
|
+
end
|
81
|
+
|
82
|
+
def polling_frequency=(value)
|
83
|
+
@polling_frequency = [value.to_i, 1].max
|
84
|
+
end
|
85
|
+
|
86
|
+
def log_level=(level)
|
87
|
+
if level.is_a?(Integer) && (0..5).include?(level)
|
88
|
+
@log_level = level
|
89
|
+
elsif level.is_a?(Symbol) || level.is_a?(String)
|
90
|
+
level_map = {
|
91
|
+
debug: Logger::DEBUG,
|
92
|
+
info: Logger::INFO,
|
93
|
+
warn: Logger::WARN,
|
94
|
+
error: Logger::ERROR,
|
95
|
+
fatal: Logger::FATAL,
|
96
|
+
unknown: Logger::UNKNOWN
|
97
|
+
}
|
98
|
+
sym_level = level.to_sym.downcase
|
99
|
+
if level_map.key?(sym_level)
|
100
|
+
@log_level = level_map[sym_level]
|
101
|
+
else
|
102
|
+
raise ArgumentError, "Invalid log level: #{level}. Valid levels are: #{level_map.keys.join(', ')}"
|
103
|
+
end
|
104
|
+
else
|
105
|
+
raise ArgumentError, "Log level must be an Integer (0-5) or one of: debug, info, warn, error, fatal, unknown"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
def handle_error(error, context = {})
|
109
|
+
if @error_handler
|
110
|
+
@error_handler.call(error, context)
|
111
|
+
else
|
112
|
+
default_error_handler.call(error, context)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def validate!
|
117
|
+
errors = []
|
118
|
+
|
119
|
+
# AWS Config
|
120
|
+
if aws_region.nil? || aws_region.empty?
|
121
|
+
errors << "aws_region is not configured"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Validate thread and message settings before queue URLs
|
125
|
+
if !poller_thread_count.positive?
|
126
|
+
errors << "poller_thread_count must be positive"
|
127
|
+
end
|
128
|
+
|
129
|
+
if !max_number_of_messages.between?(1, 10)
|
130
|
+
errors << "max_number_of_messages must be between 1 and 10"
|
131
|
+
end
|
132
|
+
|
133
|
+
if !wait_time_seconds.between?(0, 20)
|
134
|
+
errors << "wait_time_seconds must be between 0 and 20"
|
135
|
+
end
|
136
|
+
|
137
|
+
if !visibility_timeout.positive?
|
138
|
+
errors << "visibility_timeout must be positive"
|
139
|
+
end
|
140
|
+
|
141
|
+
if ![:continuous, :scheduled].include?(polling_type)
|
142
|
+
errors << "polling_type must be :continuous or :scheduled"
|
143
|
+
end
|
144
|
+
|
145
|
+
if !polling_frequency.positive?
|
146
|
+
errors << "polling_frequency must be positive"
|
147
|
+
end
|
148
|
+
|
149
|
+
# Queue URLs should be checked last
|
150
|
+
if queue_urls.empty?
|
151
|
+
errors << "queue_urls is empty"
|
152
|
+
end
|
153
|
+
|
154
|
+
# Raise first specific error for single-error tests
|
155
|
+
if errors.length == 1
|
156
|
+
raise ArgumentError, errors.first
|
157
|
+
end
|
158
|
+
|
159
|
+
# Raise all errors together
|
160
|
+
if errors.any?
|
161
|
+
raise ArgumentError, "Invalid configuration: #{errors.join(', ')}"
|
162
|
+
end
|
163
|
+
|
164
|
+
true
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def default_error_handler
|
170
|
+
->(error, context = {}) do
|
171
|
+
logger = self.logger || Sidekiq.logger
|
172
|
+
if error.is_a?(Exception)
|
173
|
+
logger.error(error.message)
|
174
|
+
logger.error(error.backtrace.join("\n")) if error.backtrace
|
175
|
+
else
|
176
|
+
logger.error(error.to_s)
|
177
|
+
end
|
178
|
+
logger.error("Context: #{context.inspect}") unless context.empty?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module SidekiqSqsProcessor
|
4
|
+
class ContinuousPoller
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@running = false
|
9
|
+
@threads = []
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
return false if running?
|
15
|
+
|
16
|
+
@mutex.synchronize do
|
17
|
+
@running = true
|
18
|
+
start_polling_threads
|
19
|
+
end
|
20
|
+
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
return false unless running?
|
26
|
+
|
27
|
+
@mutex.synchronize do
|
28
|
+
@running = false
|
29
|
+
stop_polling_threads
|
30
|
+
end
|
31
|
+
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def running?
|
36
|
+
@running
|
37
|
+
end
|
38
|
+
|
39
|
+
def stats
|
40
|
+
{
|
41
|
+
running: running?,
|
42
|
+
threads: @threads.count,
|
43
|
+
queue_urls: SidekiqSqsProcessor.configuration.queue_urls
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def start_polling_threads
|
50
|
+
SidekiqSqsProcessor.configuration.queue_urls.each do |queue_url|
|
51
|
+
SidekiqSqsProcessor.configuration.poller_thread_count.times do
|
52
|
+
thread = Thread.new do
|
53
|
+
poll_queue(queue_url) while running?
|
54
|
+
end
|
55
|
+
@threads << thread
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def stop_polling_threads
|
61
|
+
@threads.each(&:exit)
|
62
|
+
@threads.each(&:join)
|
63
|
+
@threads.clear
|
64
|
+
end
|
65
|
+
|
66
|
+
def poll_queue(queue_url)
|
67
|
+
response = receive_messages(queue_url)
|
68
|
+
process_messages(response.messages, queue_url)
|
69
|
+
rescue StandardError => e
|
70
|
+
SidekiqSqsProcessor.handle_error(e, { queue_url: queue_url })
|
71
|
+
sleep(1) # Brief pause before retrying
|
72
|
+
end
|
73
|
+
|
74
|
+
def receive_messages(queue_url)
|
75
|
+
SidekiqSqsProcessor.sqs_client.receive_message(
|
76
|
+
queue_url: queue_url,
|
77
|
+
max_number_of_messages: SidekiqSqsProcessor.configuration.max_number_of_messages,
|
78
|
+
visibility_timeout: SidekiqSqsProcessor.configuration.visibility_timeout,
|
79
|
+
wait_time_seconds: SidekiqSqsProcessor.configuration.wait_time_seconds,
|
80
|
+
attribute_names: ["All"],
|
81
|
+
message_attribute_names: ["All"]
|
82
|
+
)
|
83
|
+
end
|
84
|
+
def process_messages(messages, queue_url)
|
85
|
+
messages.each do |message|
|
86
|
+
message_data = nil
|
87
|
+
worker_class = nil
|
88
|
+
|
89
|
+
begin
|
90
|
+
# Convert to a hash for passing to the worker
|
91
|
+
message_data = {
|
92
|
+
"message_id" => message.message_id,
|
93
|
+
"receipt_handle" => message.receipt_handle,
|
94
|
+
"body" => message.body,
|
95
|
+
"attributes" => message.attributes,
|
96
|
+
"message_attributes" => message.message_attributes,
|
97
|
+
"md5_of_body" => message.md5_of_body,
|
98
|
+
"queue_url" => queue_url
|
99
|
+
}
|
100
|
+
|
101
|
+
worker_class = find_worker_for_message(message)
|
102
|
+
if worker_class
|
103
|
+
# Simply call perform_async, which will be handled appropriately in test vs prod
|
104
|
+
worker_class.perform_async(message_data)
|
105
|
+
end
|
106
|
+
rescue StandardError => e
|
107
|
+
# Handle worker error without re-raising
|
108
|
+
data_to_pass = message_data || message
|
109
|
+
handle_worker_error(e, worker_class&.name, data_to_pass, queue_url)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def handle_worker_error(error, worker_name, message, queue_url)
|
115
|
+
context = {
|
116
|
+
queue_url: queue_url,
|
117
|
+
worker: worker_name || "Unknown",
|
118
|
+
message: message
|
119
|
+
}
|
120
|
+
SidekiqSqsProcessor.handle_error(error, context)
|
121
|
+
end
|
122
|
+
|
123
|
+
def find_worker_for_message(message)
|
124
|
+
worker_name = "SqsProcessorWorker"
|
125
|
+
SidekiqSqsProcessor.find_worker_class(worker_name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'sidekiq'
|
3
|
+
|
4
|
+
module SidekiqSqsProcessor
|
5
|
+
# Rails integration for SidekiqSqsProcessor
|
6
|
+
# Handles initialization, configuration, and lifecycle management
|
7
|
+
class Railtie < Rails::Railtie
|
8
|
+
initializer "sidekiq_sqs_processor.configure_rails_initialization" do |app|
|
9
|
+
# Set default logger to Rails logger if not specified
|
10
|
+
SidekiqSqsProcessor.configuration.logger ||= Rails.logger
|
11
|
+
|
12
|
+
# Disable polling in test environment by default
|
13
|
+
if Rails.env.test? && !ENV['ENABLE_SQS_POLLING_IN_TEST']
|
14
|
+
SidekiqSqsProcessor.configuration.polling_enabled = false
|
15
|
+
end
|
16
|
+
|
17
|
+
# Disable polling in development by default unless explicitly enabled
|
18
|
+
if Rails.env.development? && !ENV['ENABLE_SQS_POLLING_IN_DEV']
|
19
|
+
SidekiqSqsProcessor.configuration.polling_enabled = false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Configure Sidekiq server middleware and lifecycle hooks
|
23
|
+
if defined?(Sidekiq)
|
24
|
+
Sidekiq.configure_server do |config|
|
25
|
+
# Start continuous poller when Sidekiq server starts
|
26
|
+
# Only if polling is enabled and type is continuous
|
27
|
+
config.on(:startup) do
|
28
|
+
if SidekiqSqsProcessor.configuration.polling_type == :continuous &&
|
29
|
+
SidekiqSqsProcessor.configuration.polling_enabled &&
|
30
|
+
SidekiqSqsProcessor.configuration.poll_on_startup
|
31
|
+
|
32
|
+
# Only run the poller in the scheduler process if using Sidekiq Enterprise
|
33
|
+
# For regular Sidekiq, this will run in every process
|
34
|
+
if !defined?(Sidekiq::Enterprise) || Sidekiq.schedule?
|
35
|
+
Rails.logger.info("Starting SidekiqSqsProcessor continuous poller")
|
36
|
+
SidekiqSqsProcessor.start_continuous_poller
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Stop continuous poller when Sidekiq server shuts down
|
42
|
+
config.on(:shutdown) do
|
43
|
+
if SidekiqSqsProcessor.continuous_poller_running?
|
44
|
+
Rails.logger.info("Stopping SidekiqSqsProcessor continuous poller")
|
45
|
+
SidekiqSqsProcessor.stop_continuous_poller
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Set up scheduled polling if enabled
|
52
|
+
if defined?(Sidekiq::Cron) &&
|
53
|
+
SidekiqSqsProcessor.configuration.polling_type == :scheduled &&
|
54
|
+
SidekiqSqsProcessor.configuration.polling_enabled
|
55
|
+
|
56
|
+
# Only set up in server mode
|
57
|
+
if Sidekiq.server?
|
58
|
+
frequency = SidekiqSqsProcessor.configuration.polling_frequency
|
59
|
+
|
60
|
+
# Convert seconds to cron expression
|
61
|
+
# Minimum 1 minute for cron
|
62
|
+
minutes = [frequency / 60, 1].max
|
63
|
+
cron_expression = minutes == 1 ? "* * * * *" : "*/#{minutes} * * * *"
|
64
|
+
|
65
|
+
# Create the cron job
|
66
|
+
Sidekiq::Cron::Job.create(
|
67
|
+
name: 'SQS Polling Job',
|
68
|
+
cron: cron_expression,
|
69
|
+
class: 'SidekiqSqsProcessor::ScheduledPoller',
|
70
|
+
queue: 'critical'
|
71
|
+
)
|
72
|
+
|
73
|
+
Rails.logger.info("Registered SidekiqSqsProcessor scheduled poller with cron: #{cron_expression}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Expose rake tasks if available
|
79
|
+
rake_tasks do
|
80
|
+
load "tasks/sidekiq_sqs_processor_tasks.rake" if File.exist?(File.join(File.dirname(__FILE__), "../tasks/sidekiq_sqs_processor_tasks.rake"))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Register Rails generators
|
84
|
+
generators do
|
85
|
+
require_relative "../generators/sidekiq_sqs_processor/install_generator"
|
86
|
+
require_relative "../generators/sidekiq_sqs_processor/worker_generator"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add local configuration options to Rails application configuration
|
90
|
+
config.after_initialize do |app|
|
91
|
+
# Validate configuration if in production
|
92
|
+
if Rails.env.production? && SidekiqSqsProcessor.configuration.polling_enabled
|
93
|
+
# Ensure configuration is valid
|
94
|
+
unless SidekiqSqsProcessor.configuration.valid?
|
95
|
+
Rails.logger.error("Invalid SidekiqSqsProcessor configuration")
|
96
|
+
SidekiqSqsProcessor.configuration.validate! # This will raise an error with details
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|