@@ -1396,6 +1396,181 @@ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFac
1396
1396
}
1397
1397
----
1398
1398
1399
+ ==== Exponential Backoff Full Jitter Error Handler
1400
+ This error handler applies an exponential backoff strategy with *full jitter*
1401
+ when retrying failed message processing. After calculating the exponential
1402
+ visibility timeout using the `ApproximateReceiveCount` message attribute, a
1403
+ random value between zero and the computed timeout is selected. The selected
1404
+ value becomes the new visibility timeout, spreading retries and helping to
1405
+ avoid spikes caused by synchronized retries.
1406
+
1407
+ [cols="2,3,1,1"]
1408
+ |===
1409
+ | Name | Description | Required | Default
1410
+ | `initialVisibilityTimeoutSeconds` | Starting visibility timeout (in seconds)
1411
+ used on the first receive attempt. | No | 100
1412
+ | `multiplier` | Factor applied to the visibility timeout after each retry. A
1413
+ value greater than 1 increases the delay exponentially. | No | 2.0
1414
+ | `maxVisibilityTimeoutSeconds` | Maximum allowed visibility timeout in seconds.
1415
+ | No | 43200
1416
+ | `randomSupplier` | Supplier for the random value used to calculate the
1417
+ jitter. | No | `ThreadLocalRandom::current`
1418
+ |===
1419
+
1420
+ NOTE: The maximum visibility timeout allowed by SQS is 43200 seconds (12 hours).
1421
+ If the value provided to the `maxVisibilityTimeoutSeconds` parameter exceeds
1422
+ this limit, an `IllegalArgumentException` will be thrown.
1423
+
1424
+ When using auto-configured factory, simply declare a `@Bean` and the error
1425
+ handler will be set
1426
+
1427
+ [source, java]
1428
+ ----
1429
+ @Bean
1430
+ public ExponentialBackoffErrorHandlerWithFullJitter<Object> asyncErrorHandler() {
1431
+ return ExponentialBackoffErrorHandlerWithFullJitter
1432
+ .builder()
1433
+ .initialVisibilityTimeoutSeconds(1)
1434
+ .multiplier(2)
1435
+ .maxVisibilityTimeoutSeconds(10)
1436
+ .build();
1437
+ }
1438
+ ----
1439
+
1440
+ Alternatively, `ExponentialBackoffErrorHandlerWithFullJitter` can be set in the
1441
+ `MessageListenerContainerFactory` or directly in the `MessageListenerContainer`:
1442
+
1443
+ [source, java]
1444
+ ----
1445
+ @Bean
1446
+ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory() {
1447
+ return SqsMessageListenerContainerFactory
1448
+ .builder()
1449
+ .sqsAsyncClientSupplier(BaseSqsIntegrationTest::createAsyncClient)
1450
+ .errorHandler(ExponentialBackoffErrorHandlerWithFullJitter
1451
+ .builder()
1452
+ .initialVisibilityTimeoutSeconds(1)
1453
+ .multiplier(2)
1454
+ .maxVisibilityTimeoutSeconds(10)
1455
+ .build())
1456
+ .build();
1457
+ }
1458
+ ----
1459
+
1460
+ ==== Exponential Backoff Half Jitter Error Handler
1461
+ This variant also computes the visibility timeout exponentially but applies
1462
+ *half jitter*. The exponential delay is halved and a random value between zero
1463
+ and this half is added to it. The resulting timeout is then used to change the
1464
+ message visibility.
1465
+
1466
+ [cols="2,3,1,1"]
1467
+ |===
1468
+ | Name | Description | Required | Default
1469
+ | `initialVisibilityTimeoutSeconds` | Starting visibility timeout (in seconds)
1470
+ used on the first receive attempt. | No | 100
1471
+ | `multiplier` | Factor applied to the visibility timeout after each retry. A
1472
+ value greater than 1 increases the delay exponentially. | No | 2.0
1473
+ | `maxVisibilityTimeoutSeconds` | Maximum allowed visibility timeout in seconds.
1474
+ | No | 43200
1475
+ | `randomSupplier` | Supplier for the random value used to calculate the
1476
+ jitter. | No | `ThreadLocalRandom::current`
1477
+ |===
1478
+
1479
+ NOTE: The maximum visibility timeout allowed by SQS is 43200 seconds (12 hours).
1480
+ If the value provided to the `maxVisibilityTimeoutSeconds` parameter exceeds
1481
+ this limit, an `IllegalArgumentException` will be thrown.
1482
+
1483
+ When using auto-configured factory, simply declare a `@Bean` and the error
1484
+ handler will be set
1485
+
1486
+ [source, java]
1487
+ ----
1488
+ @Bean
1489
+ public ExponentialBackoffErrorHandlerWithHalfJitter<Object> asyncErrorHandler() {
1490
+ return ExponentialBackoffErrorHandlerWithHalfJitter
1491
+ .builder()
1492
+ .initialVisibilityTimeoutSeconds(1)
1493
+ .multiplier(2)
1494
+ .maxVisibilityTimeoutSeconds(10)
1495
+ .build();
1496
+ }
1497
+ ----
1498
+
1499
+ Alternatively, `ExponentialBackoffErrorHandlerWithHalfJitter` can be set in the
1500
+ `MessageListenerContainerFactory` or directly in the `MessageListenerContainer`:
1501
+
1502
+ [source, java]
1503
+ ----
1504
+ @Bean
1505
+ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory() {
1506
+ return SqsMessageListenerContainerFactory
1507
+ .builder()
1508
+ .sqsAsyncClientSupplier(BaseSqsIntegrationTest::createAsyncClient)
1509
+ .errorHandler(ExponentialBackoffErrorHandlerWithHalfJitter
1510
+ .builder()
1511
+ .initialVisibilityTimeoutSeconds(1)
1512
+ .multiplier(2)
1513
+ .maxVisibilityTimeoutSeconds(10)
1514
+ .build())
1515
+ .build();
1516
+ }
1517
+ ----
1518
+
1519
+ ==== Linear Backoff Error Handler
1520
+ `LinearBackoffErrorHandler` increases the visibility timeout linearly whenever a
1521
+ message processing attempt fails. Instead of exponential growth, the timeout is
1522
+ incremented by a fixed value on each retry until the maximum is reached.
1523
+
1524
+ [cols="2,3,1,1"]
1525
+ |===
1526
+ | Name | Description | Required | Default
1527
+ | `initialVisibilityTimeoutSeconds` | Initial visibility timeout (in seconds) for
1528
+ the first processing attempt. | No | 100
1529
+ | `increment` | Amount of seconds added to the visibility timeout after each
1530
+ retry. | No | 2
1531
+ | `maxVisibilityTimeoutSeconds` | Maximum allowed visibility timeout in seconds.
1532
+ | No | 43200
1533
+ |===
1534
+
1535
+ NOTE: The maximum visibility timeout allowed by SQS is 43200 seconds (12 hours).
1536
+ If the value provided to the `maxVisibilityTimeoutSeconds` parameter exceeds
1537
+ this limit, an `IllegalArgumentException` will be thrown.
1538
+
1539
+ When using auto-configured factory, simply declare a `@Bean` and the error
1540
+ handler will be set
1541
+
1542
+ [source, java]
1543
+ ----
1544
+ @Bean
1545
+ public LinearBackoffErrorHandler<Object> asyncErrorHandler() {
1546
+ return LinearBackoffErrorHandler
1547
+ .builder()
1548
+ .initialVisibilityTimeoutSeconds(1)
1549
+ .increment(2)
1550
+ .maxVisibilityTimeoutSeconds(10)
1551
+ .build();
1552
+ }
1553
+ ----
1554
+
1555
+ Alternatively, `LinearBackoffErrorHandler` can be set in the
1556
+ `MessageListenerContainerFactory` or directly in the `MessageListenerContainer`:
1557
+
1558
+ [source, java]
1559
+ ----
1560
+ @Bean
1561
+ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory() {
1562
+ return SqsMessageListenerContainerFactory
1563
+ .builder()
1564
+ .sqsAsyncClientSupplier(BaseSqsIntegrationTest::createAsyncClient)
1565
+ .errorHandler(LinearBackoffErrorHandler
1566
+ .builder()
1567
+ .initialVisibilityTimeoutSeconds(1)
1568
+ .increment(2)
1569
+ .maxVisibilityTimeoutSeconds(10)
1570
+ .build())
1571
+ .build();
1572
+ }
1573
+ ----
1399
1574
=== Message Conversion and Payload Deserialization
1400
1575
1401
1576
Payloads are automatically deserialized from `JSON` for `@SqsListener` annotated methods using a `MappingJackson2MessageConverter`.
0 commit comments