@@ -154,6 +154,118 @@ pub struct SqsBatchResponse {
154154 pub other : serde_json:: Map < String , Value > ,
155155}
156156
157+ impl SqsBatchResponse {
158+ /// Add a failed message ID to the batch response.
159+ ///
160+ /// When processing SQS messages in batches, you can use this helper method to
161+ /// register individual message failures. Lambda will automatically return failed
162+ /// messages to the queue for reprocessing while successfully processed messages
163+ /// will be deleted.
164+ ///
165+ /// Besides `item_identifiers`, the generated struct will use default field values for [`BatchItemFailure`].
166+ ///
167+ /// **Important**: This feature requires `FunctionResponseTypes: ReportBatchItemFailures`
168+ /// to be enabled in your Lambda function's SQS event source mapping configuration.
169+ /// Without this setting, Lambda will retry the entire batch on any failure.
170+ ///
171+ /// # Example
172+ ///
173+ /// ```rust
174+ /// use aws_lambda_events::event::sqs::{SqsEvent, SqsBatchResponse};
175+ /// use lambda_runtime::{service_fn, Error, LambdaEvent};
176+ ///
177+ /// async fn function_handler(
178+ /// event: LambdaEvent<SqsEvent>,
179+ /// ) -> Result<SqsBatchResponse, Error> {
180+ /// // Start from a default response
181+ /// let mut response = SqsBatchResponse::default();
182+ ///
183+ /// for record in event.payload.records {
184+ /// let message_id = record.message_id.clone().unwrap_or_default();
185+ ///
186+ /// // Try to process the message
187+ /// if let Err(e) = process_record(&record).await {
188+ /// println!("Failed to process message {}: {}", message_id, e);
189+ ///
190+ /// // Use the helper to register the failure
191+ /// response.add_failure(message_id);
192+ /// }
193+ /// }
194+ ///
195+ /// Ok(response)
196+ /// }
197+ ///
198+ /// async fn process_record(record: &aws_lambda_events::event::sqs::SqsMessage) -> Result<(), Error> {
199+ /// // Your message processing logic here
200+ /// Ok(())
201+ /// }
202+ /// ```
203+ pub fn add_failure ( & mut self , message_id : impl Into < String > ) {
204+ self . batch_item_failures . push ( BatchItemFailure {
205+ item_identifier : message_id. into ( ) ,
206+ ..Default :: default ( )
207+ } ) ;
208+ }
209+
210+ /// Set multiple failed message IDs at once.
211+ ///
212+ /// This is a convenience method for setting all batch item failures in one call.
213+ /// It replaces any previously registered failures.
214+ ///
215+ /// Besides `item_identifiers`, the generated struct will use default field values for [`BatchItemFailure`].
216+ ///
217+ /// **Important**: This feature requires `FunctionResponseTypes: ReportBatchItemFailures`
218+ /// to be enabled in your Lambda function's SQS event source mapping configuration.
219+ /// Without this setting, Lambda will retry the entire batch on any failure.
220+ ///
221+ /// # Example
222+ ///
223+ /// ```rust
224+ /// use aws_lambda_events::event::sqs::{SqsEvent, SqsBatchResponse};
225+ /// use lambda_runtime::{service_fn, Error, LambdaEvent};
226+ ///
227+ /// async fn function_handler(
228+ /// event: LambdaEvent<SqsEvent>,
229+ /// ) -> Result<SqsBatchResponse, Error> {
230+ /// let mut failed_ids = Vec::new();
231+ ///
232+ /// for record in event.payload.records {
233+ /// let message_id = record.message_id.clone().unwrap_or_default();
234+ ///
235+ /// // Try to process the message
236+ /// if let Err(e) = process_record(&record).await {
237+ /// println!("Failed to process message {}: {}", message_id, e);
238+ /// failed_ids.push(message_id);
239+ /// }
240+ /// }
241+ ///
242+ /// // Set all failures at once
243+ /// let mut response = SqsBatchResponse::default();
244+ /// response.set_failures(failed_ids);
245+ ///
246+ /// Ok(response)
247+ /// }
248+ ///
249+ /// async fn process_record(record: &aws_lambda_events::event::sqs::SqsMessage) -> Result<(), Error> {
250+ /// // Your message processing logic here
251+ /// Ok(())
252+ /// }
253+ /// ```
254+ pub fn set_failures < I , S > ( & mut self , message_ids : I )
255+ where
256+ I : IntoIterator < Item = S > ,
257+ S : Into < String > ,
258+ {
259+ self . batch_item_failures = message_ids
260+ . into_iter ( )
261+ . map ( |id| BatchItemFailure {
262+ item_identifier : id. into ( ) ,
263+ ..Default :: default ( )
264+ } )
265+ . collect ( ) ;
266+ }
267+ }
268+
157269#[ non_exhaustive]
158270#[ derive( Clone , Debug , Default , Deserialize , Eq , PartialEq , Serialize ) ]
159271#[ serde( rename_all = "camelCase" ) ]
@@ -335,4 +447,33 @@ mod test {
335447 let reparsed: SqsApiEventObj < CustStruct > = serde_json:: from_slice ( output. as_bytes ( ) ) . unwrap ( ) ;
336448 assert_eq ! ( parsed, reparsed) ;
337449 }
450+
451+ #[ test]
452+ #[ cfg( feature = "sqs" ) ]
453+ fn example_sqs_batch_response_add_failure ( ) {
454+ let mut response = SqsBatchResponse :: default ( ) ;
455+ response. add_failure ( "msg-1" . to_string ( ) ) ;
456+ response. add_failure ( "msg-2" . to_string ( ) ) ;
457+
458+ assert_eq ! ( response. batch_item_failures. len( ) , 2 ) ;
459+ assert_eq ! ( response. batch_item_failures[ 0 ] . item_identifier, "msg-1" ) ;
460+ assert_eq ! ( response. batch_item_failures[ 1 ] . item_identifier, "msg-2" ) ;
461+ }
462+
463+ #[ test]
464+ #[ cfg( feature = "sqs" ) ]
465+ fn example_sqs_batch_response_set_failures ( ) {
466+ let mut response = SqsBatchResponse :: default ( ) ;
467+ response. set_failures ( vec ! [ "msg-1" , "msg-2" , "msg-3" ] ) ;
468+
469+ assert_eq ! ( response. batch_item_failures. len( ) , 3 ) ;
470+ assert_eq ! ( response. batch_item_failures[ 0 ] . item_identifier, "msg-1" ) ;
471+ assert_eq ! ( response. batch_item_failures[ 1 ] . item_identifier, "msg-2" ) ;
472+ assert_eq ! ( response. batch_item_failures[ 2 ] . item_identifier, "msg-3" ) ;
473+
474+ // Test that set_failures replaces existing failures
475+ response. set_failures ( vec ! [ "msg-4" . to_string( ) ] ) ;
476+ assert_eq ! ( response. batch_item_failures. len( ) , 1 ) ;
477+ assert_eq ! ( response. batch_item_failures[ 0 ] . item_identifier, "msg-4" ) ;
478+ }
338479}
0 commit comments