Repository: awspring/spring-cloud-aws (Java)

Issue:
Add maxDelayBetweenPolls to Autoconfiguration
**Type**: Bug

**Component**: "SQS"

**Describe the bug:**
We can set up some important options for SQS listener such as:
spring.cloud.aws.sqs.listener.poll-timeout=20s
spring.cloud.aws.sqs.listener.max-messages-per-poll=8
spring.cloud.aws.sqs.listener.max-concurrent-messages=8
But one of the most important things you can't set in such a way: **Delay Between Polls** or **maxDelayBetweenPolls**

io.awspring.cloud.autoconfigure.sqs.SqsAutoConfiguration use SqsProperties that for some reason doesn't contain this parameter.

**Sample**
To use it instead of just writing a string to it in application.properties, you need to do a config like this:
```
@Configuration
public class SqsListenerConfiguration {
    private final ApplicationContext applicationContext;

    public SqsListenerConfiguration(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void postConstruct() {
        var containerFactory = (SqsMessageListenerContainerFactory<SqsMessageListenerContainer<Object>>)
                applicationContext.getBean("defaultSqsListenerContainerFactory");
        containerFactory.configure(options -> options.maxDelayBetweenPolls(Duration.ofSeconds(1)));
    }
}
```



Discussion:
Hi, I've done some initial analysis and would be happy to take this on.
Hey @SammoLove , thanks for bringing this up. 

Sure, we can add that parameter to auto configuration.

Be mindful though that this parameter sets the longest it'll wait to try to make a partial poll in case there there are not enough permits left to poll for a complete batch: (maxConcurrentMessages - number of inflight messages < batch size).

If messages are being consumed fast enough, polls will happen as soon as there are enough permits available.

@krutip7, go for it, looking forward to the PR.



Patch:
diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc
index 40095040c..63a6d4175 100644
--- a/docs/src/main/asciidoc/_configprops.adoc
+++ b/docs/src/main/asciidoc/_configprops.adoc
@@ -95,7 +95,8 @@
 |spring.cloud.aws.sqs.listener.max-concurrent-messages |  | The maximum concurrent messages that can be processed simultaneously for each queue. Note that if acknowledgement batching is being used, the actual maximum number of messages inflight might be higher.
 |spring.cloud.aws.sqs.listener.max-messages-per-poll |  | The maximum number of messages to be retrieved in a single poll to SQS.
 |spring.cloud.aws.sqs.listener.poll-timeout |  | The maximum amount of time for a poll to SQS.
-|spring.cloud.aws.sqs.queue-not-found-strategy |  | 
+|spring.cloud.aws.sqs.listener.max-delay-between-polls |  | The maximum amount of time to wait between consecutive polls to SQS.
+|spring.cloud.aws.sqs.queue-not-found-strategy |  |
 |spring.cloud.aws.sqs.region |  | Overrides the default region.
 
 |===
\ No newline at end of file
diff --git a/docs/src/main/asciidoc/sqs.adoc b/docs/src/main/asciidoc/sqs.adoc
index 1f49754e7..d050cba82 100644
--- a/docs/src/main/asciidoc/sqs.adoc
+++ b/docs/src/main/asciidoc/sqs.adoc
@@ -816,6 +816,7 @@ The Spring Boot Starter for SQS provides the following auto-configuration proper
 | <<maxConcurrentMessages, `spring.cloud.aws.sqs.listener.max-inflight-messages-per-queue`>> | Maximum number of inflight messages per queue. | No | 10
 | <<maxMessagesPerPoll, `spring.cloud.aws.sqs.listener.max-messages-per-poll`>> | Maximum number of messages to be received per poll. | No | 10
 | <<pollTimeout, `spring.cloud.aws.sqs.listener.poll-timeout`>> | Maximum amount of time to wait for messages in a poll. | No | 10 seconds
+| <<maxDelayBetweenPolls, `spring.cloud.aws.sqs.listener.max-delay-between-polls`>> | Maximum amount of time to wait between polls. | No | 10 seconds
 | `spring.cloud.aws.sqs.queue-not-found-strategy`  | The strategy to be used by SqsTemplate and SqsListeners when a queue does not exist. | No | CREATE
 |===
 
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
index c06b65b29..e4bfb9386 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
@@ -136,6 +136,7 @@ private void configureProperties(SqsContainerOptionsBuilder options) {
 		mapper.from(this.sqsProperties.getListener().getMaxConcurrentMessages()).to(options::maxConcurrentMessages);
 		mapper.from(this.sqsProperties.getListener().getMaxMessagesPerPoll()).to(options::maxMessagesPerPoll);
 		mapper.from(this.sqsProperties.getListener().getPollTimeout()).to(options::pollTimeout);
+		mapper.from(this.sqsProperties.getListener().getMaxDelayBetweenPolls()).to(options::maxDelayBetweenPolls);
 	}
 
 	@Bean
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsProperties.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsProperties.java
index a83eedff2..277ac3764 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsProperties.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsProperties.java
@@ -87,6 +87,12 @@ public static class Listener {
 		@Nullable
 		private Duration pollTimeout;
 
+		/**
+		 * The maximum amount of time to wait between consecutive polls to SQS.
+		 */
+		@Nullable
+		private Duration maxDelayBetweenPolls;
+
 		@Nullable
 		public Integer getMaxConcurrentMessages() {
 			return this.maxConcurrentMessages;
@@ -113,6 +119,15 @@ public Duration getPollTimeout() {
 		public void setPollTimeout(Duration pollTimeout) {
 			this.pollTimeout = pollTimeout;
 		}
+
+		@Nullable
+		public Duration getMaxDelayBetweenPolls() {
+			return maxDelayBetweenPolls;
+		}
+
+		public void setMaxDelayBetweenPolls(Duration maxDelayBetweenPolls) {
+			this.maxDelayBetweenPolls = maxDelayBetweenPolls;
+		}
 	}
 
 }


Test patch:
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfigurationTest.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfigurationTest.java
index 9ad9bc5d6..cec8a5b44 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfigurationTest.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfigurationTest.java
@@ -152,7 +152,8 @@ void configuresFactoryComponentsAndOptions() {
 				.withPropertyValues("spring.cloud.aws.sqs.enabled:true",
 						"spring.cloud.aws.sqs.listener.max-concurrent-messages:19",
 						"spring.cloud.aws.sqs.listener.max-messages-per-poll:8",
-						"spring.cloud.aws.sqs.listener.poll-timeout:6s")
+						"spring.cloud.aws.sqs.listener.poll-timeout:6s",
+						"spring.cloud.aws.sqs.listener.max-delay-between-polls:15s")
 				.withUserConfiguration(CustomComponentsConfiguration.class, ObjectMapperConfiguration.class).run(context -> {
 					assertThat(context).hasSingleBean(SqsMessageListenerContainerFactory.class);
 					SqsMessageListenerContainerFactory<?> factory = context
@@ -168,6 +169,7 @@ void configuresFactoryComponentsAndOptions() {
 						assertThat(options.getMaxConcurrentMessages()).isEqualTo(19);
 						assertThat(options.getMaxMessagesPerPoll()).isEqualTo(8);
 						assertThat(options.getPollTimeout()).isEqualTo(Duration.ofSeconds(6));
+						assertThat(options.getMaxDelayBetweenPolls()).isEqualTo(Duration.ofSeconds(15));
 					})
 					.extracting("messageConverter")
 					.asInstanceOf(type(SqsMessagingMessageConverter.class))
@@ -195,6 +197,7 @@ void configuresFactoryComponentsAndOptionsWithDefaults() {
 					assertThat(options.getMaxConcurrentMessages()).isEqualTo(10);
 					assertThat(options.getMaxMessagesPerPoll()).isEqualTo(10);
 					assertThat(options.getPollTimeout()).isEqualTo(Duration.ofSeconds(10));
+					assertThat(options.getMaxDelayBetweenPolls()).isEqualTo(Duration.ofSeconds(10));
 				})
 				.extracting("messageConverter")
 				.asInstanceOf(type(SqsMessagingMessageConverter.class))