sqs_processor 0.1.1 → 0.1.3
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/README.md +33 -48
- data/lib/sqs_processor/processor.rb +40 -21
- data/lib/sqs_processor/version.rb +1 -1
- metadata +2 -4
- data/bin/sqs_processor +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8c84fdb30ca8f133ccf09157614bd1aff65487f384a587abe975c2b883ca338
|
4
|
+
data.tar.gz: f9177b02b2b713e1acbf5ce9fac29f9a13c48eee8454b07778df81dd7472ca09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0cae0d423be0b4605ab032007df401017836617d020f0b98062b45d8a5d7cb09b89d87111a7217199bb2b20392a29d9ea57e7904b3b72bc616c30ad66d42fcd
|
7
|
+
data.tar.gz: 25fc1ea117532b69f30a34f71b03ca844bbb9ae9c6173c500e0b81ba943db085a76e0ae2425425b90bae5c9ab6dda878618bc3e6116f7ad336d2dd8635f072e8
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ A Ruby gem for processing messages from Amazon SQS queues with configurable mess
|
|
9
9
|
- **Error Handling**: Robust error handling with message retention on failure
|
10
10
|
- **Customizable**: Extensible message processing logic
|
11
11
|
- **Logging**: Comprehensive logging with configurable levels
|
12
|
-
- **
|
12
|
+
- **Graceful Shutdown**: Handles SIGTERM, SIGINT, and SIGQUIT signals gracefully
|
13
13
|
- **Environment Variables**: Support for AWS credentials and configuration via environment variables
|
14
14
|
|
15
15
|
## Prerequisites
|
@@ -58,37 +58,7 @@ DATA_SYNC_SQS_QUEUE_URL=https://sqs.us-east-1.amazonaws.com/123456789012/your-qu
|
|
58
58
|
|
59
59
|
## Usage
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
```bash
|
64
|
-
sqs_processor [options]
|
65
|
-
```
|
66
|
-
|
67
|
-
### Command Line Options
|
68
|
-
|
69
|
-
```bash
|
70
|
-
sqs_processor [options]
|
71
|
-
|
72
|
-
Options:
|
73
|
-
-q, --queue-url URL SQS Queue URL
|
74
|
-
-r, --region REGION AWS Region
|
75
|
-
-m, --max-messages NUMBER Max messages per batch (default: 10)
|
76
|
-
-v, --visibility-timeout SECONDS Visibility timeout in seconds (default: 30)
|
77
|
-
-h, --help Show this help message
|
78
|
-
```
|
79
|
-
|
80
|
-
### Examples
|
81
|
-
|
82
|
-
```bash
|
83
|
-
# Basic usage with environment variables
|
84
|
-
sqs_processor
|
85
|
-
|
86
|
-
# Specify queue URL and region
|
87
|
-
sqs_processor -q https://sqs.us-west-2.amazonaws.com/123456789012/my-queue -r us-west-2
|
88
|
-
|
89
|
-
# Custom batch size and visibility timeout
|
90
|
-
sqs_processor -m 5 -v 60
|
91
|
-
```
|
61
|
+
The gem is designed to be used programmatically in your Ruby applications.
|
92
62
|
|
93
63
|
### Programmatic Usage
|
94
64
|
|
@@ -97,14 +67,14 @@ sqs_processor -m 5 -v 60
|
|
97
67
|
```ruby
|
98
68
|
require 'sqs_processor'
|
99
69
|
|
100
|
-
# Create a processor instance
|
70
|
+
# Create a processor instance with AWS credentials
|
101
71
|
processor = SQSProcessor::Processor.new(
|
102
72
|
queue_url: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue',
|
103
|
-
region: 'us-east-1',
|
104
|
-
max_messages: 10,
|
105
|
-
visibility_timeout: 30,
|
106
73
|
aws_access_key_id: 'your-access-key',
|
107
|
-
aws_secret_access_key: 'your-secret-key'
|
74
|
+
aws_secret_access_key: 'your-secret-key',
|
75
|
+
aws_region: 'us-east-1',
|
76
|
+
max_messages: 10,
|
77
|
+
visibility_timeout: 30
|
108
78
|
)
|
109
79
|
|
110
80
|
# Start processing messages
|
@@ -117,8 +87,7 @@ The gem uses a hook-based approach for message processing. You must implement th
|
|
117
87
|
|
118
88
|
### Hook Method
|
119
89
|
|
120
|
-
The `handle_message(
|
121
|
-
- `message`: The SQS message object (contains message_id, receipt_handle, etc.)
|
90
|
+
The `handle_message(body)` method receives:
|
122
91
|
- `body`: The parsed JSON body of the message
|
123
92
|
|
124
93
|
Return `true` if processing was successful (message will be deleted from queue), or `false` if processing failed (message will remain in queue for retry).
|
@@ -141,8 +110,8 @@ To implement custom message processing logic, create a subclass of `SQSProcessor
|
|
141
110
|
require 'sqs_processor'
|
142
111
|
|
143
112
|
class MyCustomProcessor < SQSProcessor::Processor
|
144
|
-
def handle_message(
|
145
|
-
# This method receives the
|
113
|
+
def handle_message(body)
|
114
|
+
# This method receives the parsed message body
|
146
115
|
# Return true if processing was successful, false otherwise
|
147
116
|
|
148
117
|
case body['event_type']
|
@@ -174,9 +143,9 @@ end
|
|
174
143
|
# Usage
|
175
144
|
processor = MyCustomProcessor.new(
|
176
145
|
queue_url: 'your-queue-url',
|
177
|
-
region: 'us-east-1',
|
178
146
|
aws_access_key_id: 'your-access-key',
|
179
|
-
aws_secret_access_key: 'your-secret-key'
|
147
|
+
aws_secret_access_key: 'your-secret-key',
|
148
|
+
aws_region: 'us-east-1'
|
180
149
|
)
|
181
150
|
processor.process_messages
|
182
151
|
```
|
@@ -188,13 +157,12 @@ processor.process_messages
|
|
188
157
|
The `SQSProcessor::Processor.new` method accepts the following parameters:
|
189
158
|
|
190
159
|
- `queue_url:` (required) - The SQS queue URL
|
191
|
-
- `
|
160
|
+
- `aws_access_key_id:` (required) - AWS access key ID
|
161
|
+
- `aws_secret_access_key:` (required) - AWS secret access key
|
162
|
+
- `aws_region:` (optional, default: 'us-east-1') - AWS region
|
163
|
+
- `aws_session_token:` (optional) - AWS session token for temporary credentials
|
192
164
|
- `max_messages:` (optional, default: 10) - Maximum messages per batch
|
193
165
|
- `visibility_timeout:` (optional, default: 30) - Message visibility timeout in seconds
|
194
|
-
- `aws_access_key_id:` (optional) - AWS access key ID
|
195
|
-
- `aws_secret_access_key:` (optional) - AWS secret access key
|
196
|
-
- `aws_session_token:` (optional) - AWS session token for temporary credentials
|
197
|
-
- `aws_credentials:` (optional) - Pre-configured AWS credentials object
|
198
166
|
- `logger:` (optional) - Custom logger instance
|
199
167
|
|
200
168
|
### Environment Variables
|
@@ -228,6 +196,22 @@ The script supports multiple ways to provide AWS credentials:
|
|
228
196
|
- **Network Errors**: Automatic retry with exponential backoff
|
229
197
|
- **Queue Errors**: Comprehensive error logging with stack traces
|
230
198
|
|
199
|
+
## Graceful Shutdown
|
200
|
+
|
201
|
+
The processor handles termination signals gracefully:
|
202
|
+
|
203
|
+
- **SIGTERM**: Standard termination signal (used by container orchestrators)
|
204
|
+
- **SIGINT**: Interrupt signal (Ctrl+C)
|
205
|
+
- **SIGQUIT**: Quit signal
|
206
|
+
|
207
|
+
When a shutdown signal is received:
|
208
|
+
1. The processor stops accepting new messages
|
209
|
+
2. Completes processing of any current message batch
|
210
|
+
3. Logs the shutdown process
|
211
|
+
4. Exits cleanly
|
212
|
+
|
213
|
+
This ensures that no messages are lost during deployments or process termination.
|
214
|
+
|
231
215
|
## Monitoring
|
232
216
|
|
233
217
|
The script provides detailed logging including:
|
@@ -244,6 +228,7 @@ The script provides detailed logging including:
|
|
244
228
|
3. **Handle errors gracefully**: Return `false` from processing methods to keep messages in queue
|
245
229
|
4. **Monitor queue depth**: Use the built-in queue attribute reporting
|
246
230
|
5. **Use appropriate batch sizes**: Balance between throughput and memory usage
|
231
|
+
6. **Deploy with graceful shutdown**: The processor handles SIGTERM gracefully for container deployments
|
247
232
|
|
248
233
|
## Troubleshooting
|
249
234
|
|
@@ -11,20 +11,16 @@ module SQSProcessor
|
|
11
11
|
class Processor
|
12
12
|
attr_reader :sqs_client, :queue_url, :logger
|
13
13
|
|
14
|
-
def initialize(queue_url:,
|
15
|
-
|
16
|
-
aws_credentials: nil, logger: nil)
|
14
|
+
def initialize(queue_url:, aws_access_key_id:, aws_secret_access_key:, aws_region: 'us-east-1',
|
15
|
+
aws_session_token: nil, max_messages: 10, visibility_timeout: 30, logger: nil)
|
17
16
|
@queue_url = queue_url
|
18
|
-
@region = region
|
19
17
|
@max_messages = max_messages
|
20
18
|
@visibility_timeout = visibility_timeout
|
21
|
-
@
|
22
|
-
@aws_access_key_id = aws_access_key_id
|
23
|
-
@aws_secret_access_key = aws_secret_access_key
|
24
|
-
@aws_session_token = aws_session_token
|
19
|
+
@shutdown_requested = false
|
25
20
|
|
26
21
|
setup_logger(logger)
|
27
|
-
setup_sqs_client
|
22
|
+
setup_sqs_client(aws_access_key_id, aws_secret_access_key, aws_session_token, aws_region)
|
23
|
+
setup_signal_handlers
|
28
24
|
|
29
25
|
raise 'Queue URL is required.' unless @queue_url
|
30
26
|
end
|
@@ -37,23 +33,31 @@ module SQSProcessor
|
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
|
-
def setup_sqs_client
|
41
|
-
credentials =
|
42
|
-
@aws_credentials
|
43
|
-
elsif @aws_access_key_id && @aws_secret_access_key
|
44
|
-
Aws::Credentials.new(@aws_access_key_id, @aws_secret_access_key, @aws_session_token)
|
45
|
-
elsif ENV['DATA_SYNC_AWS_ACCESS_KEY_ID'] && ENV['DATA_SYNC_AWS_SECRET_ACCESS_KEY']
|
46
|
-
Aws::Credentials.new(ENV['DATA_SYNC_AWS_ACCESS_KEY_ID'], ENV['DATA_SYNC_AWS_SECRET_ACCESS_KEY'])
|
47
|
-
else
|
48
|
-
Aws::Credentials.new
|
49
|
-
end
|
50
|
-
|
36
|
+
def setup_sqs_client(aws_access_key_id, aws_secret_access_key, aws_session_token, aws_region)
|
37
|
+
credentials = Aws::Credentials.new(aws_access_key_id, aws_secret_access_key, aws_session_token)
|
51
38
|
@sqs_client = Aws::SQS::Client.new(
|
52
|
-
region:
|
39
|
+
region: aws_region,
|
53
40
|
credentials: credentials
|
54
41
|
)
|
55
42
|
end
|
56
43
|
|
44
|
+
def setup_signal_handlers
|
45
|
+
Signal.trap('TERM') do
|
46
|
+
logger.info 'Received SIGTERM, initiating graceful shutdown...'
|
47
|
+
@shutdown_requested = true
|
48
|
+
end
|
49
|
+
|
50
|
+
Signal.trap('INT') do
|
51
|
+
logger.info 'Received SIGINT, initiating graceful shutdown...'
|
52
|
+
@shutdown_requested = true
|
53
|
+
end
|
54
|
+
|
55
|
+
Signal.trap('QUIT') do
|
56
|
+
logger.info 'Received SIGQUIT, initiating graceful shutdown...'
|
57
|
+
@shutdown_requested = true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
57
61
|
def process_messages
|
58
62
|
logger.info 'Starting SQS message processing...'
|
59
63
|
logger.info "Queue URL: #{@queue_url}"
|
@@ -61,6 +65,8 @@ module SQSProcessor
|
|
61
65
|
logger.info "Visibility timeout: #{@visibility_timeout} seconds"
|
62
66
|
|
63
67
|
loop do
|
68
|
+
break if @shutdown_requested
|
69
|
+
|
64
70
|
receive_messages
|
65
71
|
sleep 1 # Small delay between polling cycles
|
66
72
|
rescue StandardError => e
|
@@ -68,6 +74,8 @@ module SQSProcessor
|
|
68
74
|
logger.error e.backtrace.join("\n")
|
69
75
|
sleep 5 # Longer delay on error
|
70
76
|
end
|
77
|
+
|
78
|
+
logger.info 'Graceful shutdown completed.'
|
71
79
|
end
|
72
80
|
|
73
81
|
def receive_messages
|
@@ -86,6 +94,8 @@ module SQSProcessor
|
|
86
94
|
logger.info "Received #{response.messages.length} message(s)"
|
87
95
|
|
88
96
|
response.messages.each do |message|
|
97
|
+
break if @shutdown_requested
|
98
|
+
|
89
99
|
process_single_message(message)
|
90
100
|
end
|
91
101
|
end
|
@@ -149,5 +159,14 @@ module SQSProcessor
|
|
149
159
|
|
150
160
|
attributes
|
151
161
|
end
|
162
|
+
|
163
|
+
def shutdown_requested?
|
164
|
+
@shutdown_requested
|
165
|
+
end
|
166
|
+
|
167
|
+
def request_shutdown
|
168
|
+
logger.info 'Shutdown requested manually...'
|
169
|
+
@shutdown_requested = true
|
170
|
+
end
|
152
171
|
end
|
153
172
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqs_processor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Unni Tallman
|
@@ -125,14 +125,12 @@ description: A comprehensive Ruby gem for processing messages from Amazon SQS qu
|
|
125
125
|
with configurable message handling, error recovery, and extensible processing logic.
|
126
126
|
email:
|
127
127
|
- unni@bigbinary.com
|
128
|
-
executables:
|
129
|
-
- sqs_processor
|
128
|
+
executables: []
|
130
129
|
extensions: []
|
131
130
|
extra_rdoc_files: []
|
132
131
|
files:
|
133
132
|
- LICENSE
|
134
133
|
- README.md
|
135
|
-
- bin/sqs_processor
|
136
134
|
- lib/sqs_processor.rb
|
137
135
|
- lib/sqs_processor/processor.rb
|
138
136
|
- lib/sqs_processor/version.rb
|
data/bin/sqs_processor
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'sqs_processor'
|
4
|
-
require 'optparse'
|
5
|
-
|
6
|
-
def parse_options
|
7
|
-
options = {
|
8
|
-
queue_url: nil,
|
9
|
-
region: nil,
|
10
|
-
max_messages: 10,
|
11
|
-
visibility_timeout: 30
|
12
|
-
}
|
13
|
-
|
14
|
-
OptionParser.new do |opts|
|
15
|
-
opts.banner = 'Usage: sqs_processor [options]'
|
16
|
-
|
17
|
-
opts.on('-q', '--queue-url URL', 'SQS Queue URL') do |url|
|
18
|
-
options[:queue_url] = url
|
19
|
-
end
|
20
|
-
|
21
|
-
opts.on('-r', '--region REGION', 'AWS Region') do |region|
|
22
|
-
options[:region] = region
|
23
|
-
end
|
24
|
-
|
25
|
-
opts.on('-m', '--max-messages NUMBER', Integer, 'Max messages per batch (default: 10)') do |num|
|
26
|
-
options[:max_messages] = num
|
27
|
-
end
|
28
|
-
|
29
|
-
opts.on('-v', '--visibility-timeout SECONDS', Integer, 'Visibility timeout in seconds (default: 30)') do |timeout|
|
30
|
-
options[:visibility_timeout] = timeout
|
31
|
-
end
|
32
|
-
|
33
|
-
opts.on('-h', '--help', 'Show this help message') do
|
34
|
-
puts opts
|
35
|
-
exit
|
36
|
-
end
|
37
|
-
end.parse!
|
38
|
-
|
39
|
-
options
|
40
|
-
end
|
41
|
-
|
42
|
-
if __FILE__ == $0
|
43
|
-
options = parse_options
|
44
|
-
|
45
|
-
begin
|
46
|
-
# Load environment variables
|
47
|
-
Dotenv.load
|
48
|
-
|
49
|
-
# Get queue URL from options or environment
|
50
|
-
queue_url = options[:queue_url] || ENV.fetch('DATA_SYNC_SQS_QUEUE_URL', nil)
|
51
|
-
|
52
|
-
unless queue_url
|
53
|
-
puts 'Error: Queue URL is required. Set DATA_SYNC_SQS_QUEUE_URL environment variable or use -q option.'
|
54
|
-
exit 1
|
55
|
-
end
|
56
|
-
|
57
|
-
processor = SQSProcessor::Processor.new(
|
58
|
-
queue_url: queue_url,
|
59
|
-
region: options[:region] || ENV['DATA_SYNC_AWS_REGION'] || 'us-east-1',
|
60
|
-
max_messages: options[:max_messages],
|
61
|
-
visibility_timeout: options[:visibility_timeout],
|
62
|
-
aws_access_key_id: ENV.fetch('DATA_SYNC_AWS_ACCESS_KEY_ID', nil),
|
63
|
-
aws_secret_access_key: ENV.fetch('DATA_SYNC_AWS_SECRET_ACCESS_KEY', nil),
|
64
|
-
aws_session_token: ENV.fetch('DATA_SYNC_AWS_SESSION_TOKEN', nil)
|
65
|
-
)
|
66
|
-
|
67
|
-
# Show queue attributes before starting
|
68
|
-
processor.get_queue_attributes
|
69
|
-
|
70
|
-
# Start processing messages
|
71
|
-
processor.process_messages
|
72
|
-
rescue StandardError => e
|
73
|
-
puts "Error: #{e.message}"
|
74
|
-
puts e.backtrace.join("\n")
|
75
|
-
exit 1
|
76
|
-
end
|
77
|
-
end
|