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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 840d04b0ed53863a1d63d982a96adb4b44534151e2052dd508b6639e7a875f1d
|
4
|
+
data.tar.gz: 7392d9426507e8d20f9c932bedd1291ce86299a4606442602fa18b17c4ece62d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 811fce502fecb1e1fed02d8e26f9836e3059091c583370f3864739df3509308df347a07b64c2be1d66ef63923f155531e7ab0e8cbdf9a68ab679171e09eb8816
|
7
|
+
data.tar.gz: 59cd2987302ed96f7004586b9a2cdc82c2669b7fce0b2fcefd5d47f2edcc4a83bb0007a5a177988370312515d5b198617601cda50d026f3f0f414f0b2aeaef52
|
data/README.md
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
# Sidekiq SQS Processor
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/sidekiq_sqs_processor)
|
4
|
+
[](https://github.com/yourusername/sidekiq_sqs_processor/actions)
|
5
|
+
|
6
|
+
A Ruby gem that seamlessly integrates Amazon SQS with Sidekiq for efficient and scalable message processing. Process SQS messages asynchronously with the power and monitoring capabilities of Sidekiq.
|
7
|
+
|
8
|
+
## Features
|
9
|
+
|
10
|
+
- **Automatic SQS polling** - Continuously polls SQS queues for new messages
|
11
|
+
- **Parallel processing** - Process messages across multiple Sidekiq workers
|
12
|
+
- **SNS integration** - Auto-unwraps SNS notifications
|
13
|
+
- **Configurable polling strategies** - Choose between continuous or scheduled polling
|
14
|
+
- **Automatic retries** - Leverage Sidekiq's retry mechanism with SQS visibility timeout
|
15
|
+
- **Easy message routing** - Route messages to different workers based on content
|
16
|
+
- **Rails integration** - Simple setup with generators for Rails applications
|
17
|
+
- **Comprehensive monitoring** - Track processing stats and worker health
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'sidekiq_sqs_processor'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ bundle install
|
31
|
+
```
|
32
|
+
|
33
|
+
Or install it yourself:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
$ gem install sidekiq_sqs_processor
|
37
|
+
```
|
38
|
+
|
39
|
+
## Dependencies
|
40
|
+
|
41
|
+
This gem requires the following dependencies in your application:
|
42
|
+
|
43
|
+
- Sidekiq (~> 7.0)
|
44
|
+
- aws-sdk-sqs (~> 1.0)
|
45
|
+
- Rails (>= 6.0)
|
46
|
+
|
47
|
+
### Rails Setup
|
48
|
+
|
49
|
+
If you're using Rails, run the built-in generator to create the initializer and example worker:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
$ rails generate sidekiq_sqs_processor:install
|
53
|
+
```
|
54
|
+
|
55
|
+
## Basic Configuration
|
56
|
+
|
57
|
+
### Rails Applications
|
58
|
+
|
59
|
+
After running the installer, edit the generated initializer at `config/initializers/sidekiq_sqs_processor.rb`:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
SidekiqSqsProcessor.configure do |config|
|
63
|
+
# AWS region for SQS queues
|
64
|
+
config.aws_region = 'us-east-1'
|
65
|
+
|
66
|
+
# SQS queue URLs to poll
|
67
|
+
config.queue_urls = [
|
68
|
+
'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue'
|
69
|
+
]
|
70
|
+
|
71
|
+
# Polling configuration
|
72
|
+
config.polling_type = :continuous
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
### Non-Rails Applications
|
77
|
+
|
78
|
+
For non-Rails applications, add this to your initialization code:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
require 'sidekiq_sqs_processor'
|
82
|
+
|
83
|
+
SidekiqSqsProcessor.configure do |config|
|
84
|
+
# AWS region for SQS queues
|
85
|
+
config.aws_region = 'us-east-1'
|
86
|
+
|
87
|
+
# SQS queue URLs to poll
|
88
|
+
config.queue_urls = [
|
89
|
+
'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue'
|
90
|
+
]
|
91
|
+
|
92
|
+
# Start polling when Sidekiq starts
|
93
|
+
Sidekiq.configure_server do |sidekiq_config|
|
94
|
+
sidekiq_config.on(:startup) do
|
95
|
+
SidekiqSqsProcessor.start_continuous_poller
|
96
|
+
end
|
97
|
+
|
98
|
+
sidekiq_config.on(:shutdown) do
|
99
|
+
SidekiqSqsProcessor.stop_continuous_poller
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
## Creating Workers
|
106
|
+
|
107
|
+
### Using the Generator (Rails)
|
108
|
+
|
109
|
+
```bash
|
110
|
+
$ rails generate sidekiq_sqs_processor:worker UserNotification
|
111
|
+
```
|
112
|
+
|
113
|
+
This will create:
|
114
|
+
- `app/workers/user_notification_worker.rb`
|
115
|
+
- `spec/workers/user_notification_worker_spec.rb` (if using RSpec)
|
116
|
+
- or `test/workers/user_notification_worker_test.rb` (if using Test::Unit)
|
117
|
+
|
118
|
+
### Manual Worker Creation
|
119
|
+
|
120
|
+
Create a class that inherits from `SidekiqSqsProcessor::BaseWorker`:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class MyWorker < SidekiqSqsProcessor::BaseWorker
|
124
|
+
# Override the process_message method to handle your SQS messages
|
125
|
+
def process_message(message_body)
|
126
|
+
# message_body is already parsed from JSON if it was a JSON string
|
127
|
+
|
128
|
+
# Your processing logic here
|
129
|
+
User.find_by(id: message_body['user_id'])&.notify(message_body['message'])
|
130
|
+
|
131
|
+
# Return a result (optional)
|
132
|
+
{ status: 'success' }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
## Usage Examples
|
138
|
+
|
139
|
+
### Basic Message Processing
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
class OrderProcessor < SidekiqSqsProcessor::BaseWorker
|
143
|
+
def process_message(message_body)
|
144
|
+
if message_body.is_a?(Hash) && message_body['order_id']
|
145
|
+
# Process an order
|
146
|
+
process_order(message_body['order_id'], message_body['items'])
|
147
|
+
else
|
148
|
+
logger.error("Invalid order message format: #{message_body.inspect}")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def process_order(order_id, items)
|
155
|
+
# Your order processing logic
|
156
|
+
Order.process(order_id, items)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
### Handling Different Message Types
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
class EventProcessor < SidekiqSqsProcessor::BaseWorker
|
165
|
+
def process_message(message_body)
|
166
|
+
case message_body['event_type']
|
167
|
+
when 'user_created'
|
168
|
+
create_user(message_body['data'])
|
169
|
+
when 'order_placed'
|
170
|
+
process_order(message_body['data'])
|
171
|
+
when 'payment_received'
|
172
|
+
process_payment(message_body['data'])
|
173
|
+
else
|
174
|
+
logger.warn("Unknown event type: #{message_body['event_type']}")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# ... processing methods ...
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
### Handling SNS Messages
|
183
|
+
|
184
|
+
SNS messages are automatically detected and unwrapped, so the `message_body` will contain the inner message content:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
class NotificationProcessor < SidekiqSqsProcessor::BaseWorker
|
188
|
+
def process_message(message_body)
|
189
|
+
# For an SNS message, the SNS envelope has been removed
|
190
|
+
# and message_body is the parsed content of the SNS Message field
|
191
|
+
|
192
|
+
logger.info("Processing notification: #{message_body.inspect}")
|
193
|
+
# ... your processing logic ...
|
194
|
+
end
|
195
|
+
end
|
196
|
+
```
|
197
|
+
|
198
|
+
### Direct Message Enqueueing
|
199
|
+
|
200
|
+
You can also enqueue messages directly to a worker without going through SQS:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
# Enqueue a message to a specific worker
|
204
|
+
SidekiqSqsProcessor.enqueue_message(
|
205
|
+
MyWorker,
|
206
|
+
{ order_id: 123, items: ['item1', 'item2'] }
|
207
|
+
)
|
208
|
+
```
|
209
|
+
|
210
|
+
## Configuration Options
|
211
|
+
|
212
|
+
### AWS Configuration
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
config.aws_region = 'us-east-1' # AWS region
|
216
|
+
config.aws_access_key_id = 'YOUR_KEY' # Optional - uses env vars by default
|
217
|
+
config.aws_secret_access_key = 'YOUR_SECRET' # Optional - uses env vars by default
|
218
|
+
```
|
219
|
+
|
220
|
+
### SQS Configuration
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
config.queue_urls = ['https://sqs.region.amazonaws.com/account/queue']
|
224
|
+
config.visibility_timeout = 300 # 5 minutes
|
225
|
+
config.wait_time_seconds = 20 # 20 seconds (long polling)
|
226
|
+
config.max_number_of_messages = 10 # Max messages per receive call
|
227
|
+
```
|
228
|
+
|
229
|
+
### Polling Configuration
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
config.polling_type = :continuous # :continuous or :scheduled
|
233
|
+
config.polling_frequency = 60 # Only used for scheduled (seconds)
|
234
|
+
config.polling_enabled = true # Enable/disable polling
|
235
|
+
config.poll_on_startup = true # Start polling when app starts
|
236
|
+
```
|
237
|
+
|
238
|
+
### Sidekiq Configuration
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
config.worker_queue_name = 'sqs_default' # Default Sidekiq queue
|
242
|
+
config.worker_retry_count = 5 # Default retry count
|
243
|
+
```
|
244
|
+
|
245
|
+
### Error Handling
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
# Custom error handler
|
249
|
+
config.error_handler = ->(error, context) do
|
250
|
+
# Send to your error tracking service
|
251
|
+
Sentry.capture_exception(error, extra: context)
|
252
|
+
end
|
253
|
+
```
|
254
|
+
|
255
|
+
## Best Practices
|
256
|
+
|
257
|
+
### Message Structure
|
258
|
+
|
259
|
+
For best routing and processing, use structured JSON messages:
|
260
|
+
|
261
|
+
```json
|
262
|
+
{
|
263
|
+
"type": "order_placed",
|
264
|
+
"data": {
|
265
|
+
"order_id": "12345",
|
266
|
+
"customer_id": "67890",
|
267
|
+
"items": [
|
268
|
+
{"id": "item1", "quantity": 2},
|
269
|
+
{"id": "item2", "quantity": 1}
|
270
|
+
]
|
271
|
+
},
|
272
|
+
"metadata": {
|
273
|
+
"source": "web",
|
274
|
+
"timestamp": "2025-04-21T10:15:30Z"
|
275
|
+
}
|
276
|
+
}
|
277
|
+
```
|
278
|
+
|
279
|
+
### Worker Organization
|
280
|
+
|
281
|
+
- Create separate workers for different message types or domains
|
282
|
+
- Use class inheritance for common processing logic
|
283
|
+
- Keep workers small and focused
|
284
|
+
|
285
|
+
### Error Handling
|
286
|
+
|
287
|
+
- Use the `error_handler` config option for global error reporting
|
288
|
+
- Implement custom error handling in your workers for specific cases
|
289
|
+
- Let Sidekiq handle retries for transient failures
|
290
|
+
|
291
|
+
### Visibility Timeout
|
292
|
+
|
293
|
+
- Set your SQS visibility timeout longer than your Sidekiq job timeout
|
294
|
+
- A good rule of thumb: visibility_timeout = (average_processing_time * 5) + max_retry_delay
|
295
|
+
|
296
|
+
### Message Size Limits
|
297
|
+
|
298
|
+
Remember that SQS has a 256KB message size limit. For larger data:
|
299
|
+
- Store the data externally (e.g., S3) and include a reference in the message
|
300
|
+
- Split large datasets across multiple messages
|
301
|
+
|
302
|
+
## Development
|
303
|
+
|
304
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
305
|
+
|
306
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
307
|
+
|
308
|
+
## Contributing
|
309
|
+
|
310
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/sidekiq_sqs_processor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/yourusername/sidekiq_sqs_processor/blob/master/CODE_OF_CONDUCT.md).
|
311
|
+
|
312
|
+
## License
|
313
|
+
|
314
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
315
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module SidekiqSqsProcessor
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
desc "Creates a SidekiqSqsProcessor initializer and configuration for your Rails application."
|
9
|
+
|
10
|
+
class_option :queue_urls, type: :array, default: [],
|
11
|
+
desc: "List of SQS queue URLs to process"
|
12
|
+
|
13
|
+
class_option :continuous, type: :boolean, default: true,
|
14
|
+
desc: "Use continuous polling (true) or scheduled polling (false)"
|
15
|
+
|
16
|
+
class_option :queue_name, type: :string, default: "default",
|
17
|
+
desc: "Default Sidekiq queue name for the worker"
|
18
|
+
|
19
|
+
class_option :aws_region, type: :string, default: 'us-east-1',
|
20
|
+
desc: "AWS region for SQS queues"
|
21
|
+
|
22
|
+
def create_initializer_file
|
23
|
+
template "initializer.rb.tt", "config/initializers/sidekiq_sqs_processor.rb"
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_example_worker
|
27
|
+
template "worker.rb.tt", "app/workers/example_sqs_worker.rb"
|
28
|
+
end
|
29
|
+
|
30
|
+
def show_readme
|
31
|
+
readme "README.txt" if behavior == :invoke
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def continuous_polling?
|
37
|
+
options[:continuous]
|
38
|
+
end
|
39
|
+
|
40
|
+
def polling_type
|
41
|
+
continuous_polling? ? ':continuous' : ':scheduled'
|
42
|
+
end
|
43
|
+
|
44
|
+
def queue_urls
|
45
|
+
urls = options[:queue_urls]
|
46
|
+
if urls.empty?
|
47
|
+
"[] # Add your queue URLs here, e.g. ['https://sqs.us-east-1.amazonaws.com/123456789012/my-queue']"
|
48
|
+
else
|
49
|
+
urls.inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def aws_region
|
54
|
+
options[:aws_region]
|
55
|
+
end
|
56
|
+
|
57
|
+
def worker_class_name
|
58
|
+
"ExampleSqsWorker"
|
59
|
+
end
|
60
|
+
|
61
|
+
def queue_name
|
62
|
+
options[:queue_name]
|
63
|
+
end
|
64
|
+
|
65
|
+
def retry_option
|
66
|
+
", retry: 2" # Default Sidekiq retry behavior
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
=== SidekiqSqsProcessor Installation ===
|
3
|
+
|
4
|
+
SidekiqSqsProcessor has been installed in your Rails application.
|
5
|
+
|
6
|
+
== Next Steps ==
|
7
|
+
|
8
|
+
1. Review and update the configuration in:
|
9
|
+
config/initializers/sidekiq_sqs_processor.rb
|
10
|
+
|
11
|
+
Make sure to set your SQS queue URLs!
|
12
|
+
|
13
|
+
2. Check the example worker:
|
14
|
+
app/workers/example_sqs_worker.rb
|
15
|
+
|
16
|
+
Update it to handle your specific message types.
|
17
|
+
|
18
|
+
3. Run Sidekiq to start processing messages:
|
19
|
+
bundle exec sidekiq
|
20
|
+
|
21
|
+
== Worker Generation ==
|
22
|
+
|
23
|
+
To create additional SQS message workers:
|
24
|
+
|
25
|
+
$ rails generate sidekiq_sqs_processor:worker UserNotification
|
26
|
+
|
27
|
+
This will create:
|
28
|
+
app/workers/user_notification_worker.rb
|
29
|
+
spec/workers/user_notification_worker_spec.rb (if using RSpec)
|
30
|
+
|
31
|
+
== Advanced Configuration ==
|
32
|
+
|
33
|
+
* Set AWS credentials in your environment variables:
|
34
|
+
export AWS_ACCESS_KEY_ID=your_key
|
35
|
+
export AWS_SECRET_ACCESS_KEY=your_secret
|
36
|
+
|
37
|
+
* Configure Sidekiq as usual in config/sidekiq.yml
|
38
|
+
|
39
|
+
* Enable polling in development mode:
|
40
|
+
export ENABLE_SQS_POLLING_IN_
|
41
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
# SidekiqSqsProcessor configuration
|
3
|
+
SidekiqSqsProcessor.configure do |config|
|
4
|
+
# AWS credentials and region
|
5
|
+
# By default, SidekiqSqsProcessor will use the following credential sources (in order):
|
6
|
+
# 1. AWS SDK's default credential provider chain:
|
7
|
+
# - Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
|
8
|
+
# - Shared credentials file (~/.aws/credentials)
|
9
|
+
# - EC2 instance profile or ECS task role
|
10
|
+
#
|
11
|
+
# Uncomment the lines below to explicitly set credentials
|
12
|
+
# config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
|
13
|
+
# config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
|
14
|
+
|
15
|
+
# AWS region for SQS queues
|
16
|
+
config.aws_region = '<%= aws_region %>'
|
17
|
+
|
18
|
+
# SQS queue URLs (required)
|
19
|
+
# A list of SQS queue URLs to poll for messages
|
20
|
+
config.queue_urls = <%= queue_urls %>
|
21
|
+
|
22
|
+
# SQS message options
|
23
|
+
config.visibility_timeout = 300 # 5 minutes
|
24
|
+
config.wait_time_seconds = 20 # 20 seconds (long polling)
|
25
|
+
config.max_number_of_messages = 10 # Max messages per receive call
|
26
|
+
|
27
|
+
# Polling configuration
|
28
|
+
config.polling_type = <%= polling_type %> # :continuous or :scheduled
|
29
|
+
config.polling_frequency = 60 # Only used for scheduled polling (in seconds)
|
30
|
+
|
31
|
+
<% if Rails.env.development? %>
|
32
|
+
# Disable polling in development by default
|
33
|
+
# Set ENABLE_SQS_POLLING_IN_DEV=true to enable
|
34
|
+
config.polling_enabled = ENV['ENABLE_SQS_POLLING_IN_DEV'] == 'true'
|
35
|
+
<% else %>
|
36
|
+
config.polling_enabled = true # Enable polling in production
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
# Start polling when the application starts
|
40
|
+
config.poll_on_startup = true
|
41
|
+
|
42
|
+
# Sidekiq options
|
43
|
+
config.worker_queue_name = 'sqs_default' # Default queue name for SQS worker jobs
|
44
|
+
config.worker_retry_count = 5 # Number of retries for failed jobs
|
45
|
+
|
46
|
+
# Default message routing
|
47
|
+
# If set, all messages will be routed to this worker class
|
48
|
+
# If nil, will attempt to determine worker from message content
|
49
|
+
# config.default_worker_class = 'ExampleSqsWorker'
|
50
|
+
|
51
|
+
# Custom error handling (optional)
|
52
|
+
# Uncomment to add custom error reporting (e.g., to a monitoring service)
|
53
|
+
# config.error_handler = ->(error, context) do
|
54
|
+
# # Report to your error monitoring service
|
55
|
+
# Raven.capture_exception(error, extra: context) if defined?(Raven)
|
56
|
+
# Rails.logger.error("SQS Error: #{error.message}\nContext: #{context.inspect}")
|
57
|
+
# end
|
58
|
+
|
59
|
+
# Set logger - by default uses Rails.logger
|
60
|
+
config.logger = Rails.logger
|
61
|
+
config.log_level = Rails.env.production? ? Logger::INFO : Logger::DEBUG
|
62
|
+
end
|
63
|
+
|
64
|
+
# If using sidekiq-cron for scheduled polling, the Railtie will
|
65
|
+
# automatically set up the cron job based on your configuration.
|
66
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
class <%= worker_class_name %> < SidekiqSqsProcessor::BaseWorker
|
3
|
+
# Configure Sidekiq options if needed
|
4
|
+
sidekiq_options queue: '<%= queue_name %>'<%= retry_option %>
|
5
|
+
|
6
|
+
# Process an SQS message
|
7
|
+
# @param message_body [Hash, String] The parsed message body
|
8
|
+
# @return [Any] Result of processing (will be logged)
|
9
|
+
def process_message(message_body)
|
10
|
+
# Log the message content
|
11
|
+
logger.info("Processing message: #{message_body.inspect}")
|
12
|
+
|
13
|
+
# Your message processing logic goes here
|
14
|
+
#
|
15
|
+
# Example: Handle different message types based on content
|
16
|
+
if message_body.is_a?(Hash)
|
17
|
+
case message_body['type']
|
18
|
+
when 'user_created'
|
19
|
+
process_user_created(message_body['data'])
|
20
|
+
when 'order_placed'
|
21
|
+
process_order_placed(message_body['data'])
|
22
|
+
else
|
23
|
+
process_generic_hash(message_body)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
process_generic_message(message_body)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return success result (optional)
|
30
|
+
{ status: 'success' }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def process_user_created(user_data)
|
36
|
+
logger.info("Processing user created event")
|
37
|
+
# Your user creation logic here
|
38
|
+
# Example:
|
39
|
+
# User.create!(user_data)
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_order_placed(order_data)
|
43
|
+
logger.info("Processing order placed event")
|
44
|
+
# Your order processing logic here
|
45
|
+
# Example:
|
46
|
+
# OrderProcessor.new(order_data).process
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_generic_hash(data)
|
50
|
+
logger.info("Processing generic hash data with keys: #{data.keys.join(', ')}")
|
51
|
+
# Generic hash handling
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_generic_message(message)
|
55
|
+
logger.info("Processing generic message: #{message}")
|
56
|
+
# Generic message handling
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
require 'rails_helper'
|
3
|
+
|
4
|
+
RSpec.describe <%= worker_class_name %> do
|
5
|
+
let(:worker) { described_class.new }
|
6
|
+
|
7
|
+
describe '#process_message' do
|
8
|
+
context 'with a hash message' do
|
9
|
+
let(:message) { { 'type' => 'user_created', 'data' => { 'name' => 'Test User' } } }
|
10
|
+
|
11
|
+
it 'processes the message correctly' do
|
12
|
+
expect(worker).to receive(:process_user_created).with(message['data'])
|
13
|
+
result = worker.process_message(message)
|
14
|
+
expect(result).to eq(status: 'success')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with a string message' do
|
19
|
+
let(:message) { 'test message' }
|
20
|
+
|
21
|
+
it 'processes the message correctly' do
|
22
|
+
expect(worker).to receive(:process_generic_message).with(message)
|
23
|
+
result = worker.process_message(message)
|
24
|
+
expect(result).to eq(status: 'success')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'SQS integration' do
|
30
|
+
it 'correctly deletes the message from SQS when processing succeeds' do
|
31
|
+
# Create a test message that simulates SQS format
|
32
|
+
message_data = {
|
33
|
+
'receipt_handle' => 'test-receipt-handle',
|
34
|
+
'queue_url' => 'https://sqs.us-east-1.amazonaws.com/123456789012/test-queue',
|
35
|
+
'message_id' => 'test-message-id',
|
36
|
+
'body' => '{"type":"test","data":{"id":123}}'
|
37
|
+
}
|
38
|
+
|
39
|
+
# Mock the SQS client
|
40
|
+
sqs_client = instance_double(Aws::SQS::Client)
|
41
|
+
allow(SidekiqSqsProcessor).to receive(:sqs_client).and_return(sqs_client)
|
42
|
+
|
43
|
+
# Expect delete_message to be called
|
44
|
+
expect(sqs_client).to receive(:delete_message).with(
|
45
|
+
queue_url: message_data['queue_url'],
|
46
|
+
receipt_handle: message_data['receipt_handle']
|
47
|
+
)
|
48
|
+
|
49
|
+
# Perform the job
|
50
|
+
worker.perform(message_data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class <%= worker_class_name %>Test < ActiveSupport::TestCase
|
5
|
+
setup do
|
6
|
+
@worker = <%= worker_class_name %>.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "processes a hash message correctly" do
|
10
|
+
message = { 'type' => 'user_created', 'data' => { 'name' => 'Test User' } }
|
11
|
+
|
12
|
+
@worker.expects(:process_user_created).with(message['data'])
|
13
|
+
result = @worker.process_message(message)
|
14
|
+
|
15
|
+
assert_equal({ status: 'success' }, result)
|
16
|
+
end
|
17
|
+
|
18
|
+
test "processes a string message correctly" do
|
19
|
+
message = 'test message'
|
20
|
+
|
21
|
+
@worker.expects(:process_generic_message).with(message)
|
22
|
+
result = @worker.process_message(message)
|
23
|
+
|
24
|
+
assert_equal({ status: 'success' }, result)
|
25
|
+
end
|
26
|
+
|
27
|
+
test "deletes the message from SQS when processing succeeds" do
|
28
|
+
# Create a test message that simulates SQS format
|
29
|
+
message_data = {
|
30
|
+
'receipt_handle' => 'test-receipt-handle',
|
31
|
+
'queue_url' => 'https://sqs.us-east-1.amazonaws.com/123456789012/test-queue',
|
32
|
+
'message_id' => 'test-message-id',
|
33
|
+
'body' => '{"type":"test","data":{"id":123}}'
|
34
|
+
}
|
35
|
+
|
36
|
+
# Mock the SQS client
|
37
|
+
sqs_client = mock()
|
38
|
+
SidekiqSqsProcessor.stubs(:sqs_client).returns(sqs_client)
|
39
|
+
|
40
|
+
# Expect delete_message to be called
|
41
|
+
sqs_client.expects(:delete_message).with(
|
42
|
+
queue_url: message_data['queue_url'],
|
43
|
+
receipt_handle: message_data['receipt_handle']
|
44
|
+
)
|
45
|
+
|
46
|
+
# Perform the job
|
47
|
+
@worker.perform(message_data)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|