3
3
"""
4
4
Batch SQS utilities
5
5
"""
6
- from typing import List , Optional , Tuple
6
+ import logging
7
+ from typing import Callable , Dict , List , Optional , Tuple
7
8
8
9
import boto3
9
10
from botocore .config import Config
10
11
12
+ from ...middleware_factory import lambda_handler_decorator
11
13
from .base import BasePartialProcessor
14
+ from .exceptions import SQSBatchProcessingError
15
+
16
+ logger = logging .getLogger (__name__ )
12
17
13
18
14
19
class PartialSQSProcessor (BasePartialProcessor ):
15
20
"""
16
21
Amazon SQS batch processor to delete successes from the Queue.
17
22
18
- Only the **special** case of partial failure is handled, thus a batch in
19
- which all records failed is **not** going to be removed from the queue, and
20
- the same is valid for a full success .
23
+ The whole batch will be processed, even if failures occur. After all records are processed,
24
+ SQSBatchProcessingError will be raised if there were any failures, causing messages to
25
+ be returned to the SQS queue. This behaviour can be disabled by passing suppress_exception .
21
26
22
27
Parameters
23
28
----------
24
29
config: Config
25
30
botocore config object
31
+ suppress_exception: bool, optional
32
+ Supress exception raised if any messages fail processing, by default False
33
+
26
34
27
35
Example
28
36
-------
@@ -46,12 +54,13 @@ class PartialSQSProcessor(BasePartialProcessor):
46
54
>>> return result
47
55
"""
48
56
49
- def __init__ (self , config : Optional [Config ] = None ):
57
+ def __init__ (self , config : Optional [Config ] = None , suppress_exception : bool = False ):
50
58
"""
51
59
Initializes sqs client.
52
60
"""
53
61
config = config or Config ()
54
62
self .client = boto3 .client ("sqs" , config = config )
63
+ self .suppress_exception = suppress_exception
55
64
56
65
super ().__init__ ()
57
66
@@ -97,10 +106,76 @@ def _clean(self):
97
106
"""
98
107
Delete messages from Queue in case of partial failure.
99
108
"""
100
- if not (self .fail_messages and self .success_messages ):
109
+ # If all messages were successful, fall back to the default SQS -
110
+ # Lambda behaviour which deletes messages if Lambda responds successfully
111
+ if not self .fail_messages :
112
+ logger .debug (f"All { len (self .success_messages )} records successfully processed" )
101
113
return
102
114
103
115
queue_url = self ._get_queue_url ()
104
116
entries_to_remove = self ._get_entries_to_clean ()
105
117
106
- return self .client .delete_message_batch (QueueUrl = queue_url , Entries = entries_to_remove )
118
+ delete_message_response = self .client .delete_message_batch (QueueUrl = queue_url , Entries = entries_to_remove )
119
+
120
+ if self .suppress_exception :
121
+ logger .debug (f"{ len (self .fail_messages )} records failed processing, but exceptions are suppressed" )
122
+ else :
123
+ logger .debug (f"{ len (self .fail_messages )} records failed processing, raising exception" )
124
+ raise SQSBatchProcessingError (list (self .exceptions ))
125
+
126
+ return delete_message_response
127
+
128
+
129
+ @lambda_handler_decorator
130
+ def sqs_batch_processor (
131
+ handler : Callable ,
132
+ event : Dict ,
133
+ context : Dict ,
134
+ record_handler : Callable ,
135
+ config : Optional [Config ] = None ,
136
+ suppress_exception : bool = False ,
137
+ ):
138
+ """
139
+ Middleware to handle SQS batch event processing
140
+
141
+ Parameters
142
+ ----------
143
+ handler: Callable
144
+ Lambda's handler
145
+ event: Dict
146
+ Lambda's Event
147
+ context: Dict
148
+ Lambda's Context
149
+ record_handler: Callable
150
+ Callable to process each record from the batch
151
+ config: Config
152
+ botocore config object
153
+ suppress_exception: bool, optional
154
+ Supress exception raised if any messages fail processing, by default False
155
+
156
+ Examples
157
+ --------
158
+ **Processes Lambda's event with PartialSQSProcessor**
159
+ >>> from aws_lambda_powertools.utilities.batch import sqs_batch_processor
160
+ >>>
161
+ >>> def record_handler(record):
162
+ >>> return record["body"]
163
+ >>>
164
+ >>> @sqs_batch_processor(record_handler=record_handler)
165
+ >>> def handler(event, context):
166
+ >>> return {"StatusCode": 200}
167
+
168
+ Limitations
169
+ -----------
170
+ * Async batch processors
171
+
172
+ """
173
+ config = config or Config ()
174
+ processor = PartialSQSProcessor (config = config , suppress_exception = suppress_exception )
175
+
176
+ records = event ["Records" ]
177
+
178
+ with processor (records , record_handler ):
179
+ processor .process ()
180
+
181
+ return handler (event , context )
0 commit comments