0

I have an application with Springboot and AWS Cloud SQS and I want to test it using Localstack.

All my tests run with a green status successfully, but my terminal is full of errors. The errors are as far as I can tell two:

  • Error polling for messages in queue my-queue.
  • Error acknowledging in queue my-queue messages bd279293-6f3e-4a15-b396-29fcdbeceef1 in 234ms

It seems that my tests completes successfully and starts to shutdown while there are some futures in the background are still trying to do some work.

I am not sure who is at fault here: SQSLister, Localstack, JUnit. Maybe it's a combination.

I would like to remove this errors because they are polluting my builds.

Code:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Service
    @RequiredArgsConstructor
    public static class Consumer {

        private final MyService myService;

        @SqsListener(queueNames = {"my-queue"})
        void listen(String message) {
            myService.doSomething(message);
        }
    }

    @Service
    public static class MyService {
        public void doSomething(String message) {
            System.out.println(message);
        }
    }
}

Test:

@SpringBootTest
@Testcontainers
class ConsumerIT {
    private static final String QUEUE_NAME = "my-queue";

    @Container
    static final LocalStackContainer localStack =
            new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.0.2")).withServices(SQS);

    @DynamicPropertySource
    static void configure(DynamicPropertyRegistry registry) {
        registry.add("spring.cloud.aws.credentials.access-key", () -> localStack.getAccessKey());
        registry.add("spring.cloud.aws.credentials.secret-key", () -> localStack.getSecretKey());
        registry.add("spring.cloud.aws.region.static", () -> localStack.getRegion());
        registry.add("spring.cloud.aws.sqs.endpoint", () -> localStack.getEndpointOverride(SQS));
    }

    @BeforeAll
    static void init() throws Exception {
        localStack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", QUEUE_NAME);
    }

    @Autowired
    SqsTemplate sqsTemplate;

    @MockitoBean
    Application.MyService myService;

    @Test
    void messageIsReceived() {
        sqsTemplate.sendAsync(x -> x.queue(QUEUE_NAME).payload("hello world")).join();

        await().atMost(Duration.ofSeconds(20)).untilAsserted(() -> {
            Mockito.verify(myService).doSomething("hello world");
        });
    }
}

(Redacted) Stack trace:

2025-02-19T11:28:31.141+01:00  INFO 57865 --- [           main] c.sample.samplesqslocalstack.ConsumerIT  : Starting ConsumerIT using Java 21.0.3 with PID 57865 (started by al in /Users/al/Downloads/sample-sqs-localstack)
...
2025-02-19T11:28:32.374+01:00  INFO 57865 --- [ecycle-thread-1] a.c.s.l.AbstractMessageListenerContainer : Container io.awspring.cloud.sqs.sqsListenerEndpointContainer#0 started
2025-02-19T11:28:32.380+01:00  INFO 57865 --- [           main] c.sample.samplesqslocalstack.ConsumerIT  : Started ConsumerIT in 1.374 seconds (process running for 8.57)
2025-02-19T11:28:32.849+01:00 ERROR 57865 --- [nc-response-1-7] i.a.c.s.l.s.AbstractPollingMessageSource : Error polling for messages in queue my-queue.

java.util.concurrent.CompletionException: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.utils.CompletableFutureUtils.errorAsCompletionException(CompletableFutureUtils.java:64) ~[utils-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncExecutionFailureExceptionReportingStage.lambda$execute$0(AsyncExecutionFailureExceptionReportingStage.java:51) ~[sdk-core-2.29.52.jar:na]
    at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2194) ~[na:na]
    at software.amazon.awssdk.utils.CompletableFutureUtils.lambda$forwardExceptionTo$0(CompletableFutureUtils.java:78) ~[utils-2.29.52.jar:na]
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863) ~[na:na]
...
Caused by: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:111) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.exception.SdkClientException.create(SdkClientException.java:47) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:226) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:221) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.maybeRetryExecute(AsyncRetryableStage2.java:151) ~[sdk-core-2.29.52.jar:na]
    ... 23 common frames omitted
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 1 failure: Unable to execute HTTP request: The connection was closed during the request. The request will usually succeed on a retry, but if it does not: consider disabling any proxies you have configured, enabling debug logging, or performing a TCP dump to identify the root cause. If this is a streaming operation, validate that data is being read or written in a timely manner. Channel Information: ChannelDiagnostics(channel=[id: 0x51147413, L:/127.0.0.1:62541 ! R:/127.0.0.1:62508], channelAge=PT0.138547S, requestCount=1, responseCount=0)
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 2 failure: Unable to execute HTTP request: Connection reset
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 3 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:62508
Caused by: java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682) ~[na:na]
    at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:973) ~[na:na]
...

2025-02-19T11:28:33.617+01:00 ERROR 57865 --- [c-response-1-11] i.a.c.s.l.a.SqsAcknowledgementExecutor   : Error acknowledging in queue my-queue messages bd279293-6f3e-4a15-b396-29fcdbeceef1 in 234ms
io.awspring.cloud.sqs.SqsAcknowledgementException: Error acknowledging messages bd279293-6f3e-4a15-b396-29fcdbeceef1
    at io.awspring.cloud.sqs.listener.acknowledgement.SqsAcknowledgementExecutor.createAcknowledgementException(SqsAcknowledgementExecutor.java:88) ~[spring-cloud-aws-sqs-3.3.0.jar:3.3.0]
    at io.awspring.cloud.sqs.listener.acknowledgement.SqsAcknowledgementExecutor.lambda$deleteMessages$3(SqsAcknowledgementExecutor.java:100) ~[spring-cloud-aws-sqs-3.3.0.jar:3.3.0]
    at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:990) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:974) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2194) ~[na:na]
...
Caused by: java.util.concurrent.CompletionException: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.utils.CompletableFutureUtils.errorAsCompletionException(CompletableFutureUtils.java:64) ~[utils-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncExecutionFailureExceptionReportingStage.lambda$execute$0(AsyncExecutionFailureExceptionReportingStage.java:51) ~[sdk-core-2.29.52.jar:na]
    at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
    ... 32 common frames omitted
Caused by: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:111) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.exception.SdkClientException.create(SdkClientException.java:47) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:226) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:221) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.maybeRetryExecute(AsyncRetryableStage2.java:151) ~[sdk-core-2.29.52.jar:na]
    ... 23 common frames omitted
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 1 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 2 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 3 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:62508
Caused by: java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682) ~[na:na]
...

2025-02-19T11:28:33.619+01:00 ERROR 57865 --- [c-response-1-11] AbstractOrderingAcknowledgementProcessor : Acknowledgement processing has thrown an error for messages bd279293-6f3e-4a15-b396-29fcdbeceef1 in io.awspring.cloud.sqs.sqsListenerEndpointContainer#0-0

java.util.concurrent.CompletionException: io.awspring.cloud.sqs.SqsAcknowledgementException: Error acknowledging messages bd279293-6f3e-4a15-b396-29fcdbeceef1
    at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:368) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.completeRelay(CompletableFuture.java:377) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1152) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2194) ~[na:na]
...
Caused by: io.awspring.cloud.sqs.SqsAcknowledgementException: Error acknowledging messages bd279293-6f3e-4a15-b396-29fcdbeceef1
    at io.awspring.cloud.sqs.listener.acknowledgement.SqsAcknowledgementExecutor.createAcknowledgementException(SqsAcknowledgementExecutor.java:88) ~[spring-cloud-aws-sqs-3.3.0.jar:3.3.0]
    at io.awspring.cloud.sqs.listener.acknowledgement.SqsAcknowledgementExecutor.lambda$deleteMessages$3(SqsAcknowledgementExecutor.java:100) ~[spring-cloud-aws-sqs-3.3.0.jar:3.3.0]
    at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:990) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:974) ~[na:na]
    ... 47 common frames omitted
Caused by: java.util.concurrent.CompletionException: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.utils.CompletableFutureUtils.errorAsCompletionException(CompletableFutureUtils.java:64) ~[utils-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncExecutionFailureExceptionReportingStage.lambda$execute$0(AsyncExecutionFailureExceptionReportingStage.java:51) ~[sdk-core-2.29.52.jar:na]
    at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
    ... 32 common frames omitted
Caused by: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:111) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.exception.SdkClientException.create(SdkClientException.java:47) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:226) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper2.setLastException(RetryableStageHelper2.java:221) ~[sdk-core-2.29.52.jar:na]
    at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.maybeRetryExecute(AsyncRetryableStage2.java:151) ~[sdk-core-2.29.52.jar:na]
    ... 23 common frames omitted
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 1 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 2 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
    Suppressed: software.amazon.awssdk.core.exception.SdkClientException: Request attempt 3 failure: Unable to execute HTTP request: Connection refused: /127.0.0.1:62508
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:62508
Caused by: java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682) ~[na:na]
...

2025-02-19T11:28:33.668+01:00  INFO 57865 --- [ecycle-thread-3] a.c.s.l.AbstractMessageListenerContainer : Container io.awspring.cloud.sqs.sqsListenerEndpointContainer#0 stopped

2 Answers 2

1

It seams you have something like this: @SqsListener("my-queue") at some class in your app.
i'm suppose this:

@Service
public class MyClassWithSqsListener {

    @SqsListener("my-queue")
    public void myListener(Object object){
        // doSomething();
    }
}

So, to avoid this errors, in your test class you can create a mock of the previous class :

@SpringBootTest
@Testcontainers
class ConsumerIT {
    private static final String QUEUE_NAME = "my-queue";

    @Container
    static final LocalStackContainer localStack =
            new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.0.2")).withServices(SQS);

    // Mock
    @MockitoBean
    private MyClassWithSqsListener myClass;
...
}
Sign up to request clarification or add additional context in comments.

Comments

0

I had the same errors when my Integration Test was successfully passing.

So to fix:

Error acknowledging messages ...

I added to the test a check if the queue is empty (which makes sure the acknowledging process was finished).

To fix multiple:

Connection refused: /127.0.0.1:62508 ...

because the Listener is still trying to poll for messages after test passed and localStack container was stopped, I tried to manipulate MessageListenerContainerRegistry() to stop it before I call localStack.stop(), but it was overkill and messy, so I found that you can simply destroy the spring application context after the test run and the listener will shut down.

Added this annotation to the test class:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

Your class should look like this:

@SpringBootTest
@Testcontainers
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class ConsumerIT {
    private static final String QUEUE_NAME = "my-queue";

    @Container
    static final LocalStackContainer localStack =
            new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.0.2")).withServices(SQS);

    @DynamicPropertySource
    static void configure(DynamicPropertyRegistry registry) {
        registry.add("spring.cloud.aws.credentials.access-key", localStack::getAccessKey);
        registry.add("spring.cloud.aws.credentials.secret-key", localStack::getSecretKey);
        registry.add("spring.cloud.aws.region.static", localStack::getRegion);
        registry.add("spring.cloud.aws.sqs.endpoint", () -> localStack.getEndpointOverride(SQS).toString());
    }

    @BeforeAll
    static void init() throws Exception {
        localStack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", QUEUE_NAME);
    }

    @Autowired
    SqsTemplate sqsTemplate;

    @Autowired
    AmazonSQS amazonSQS;

    @MockitoBean
    Application.MyService myService;

    @Test
    void messageIsReceived() {
        sqsTemplate.sendAsync(x -> x.queue(QUEUE_NAME).payload("hello world")).join();

        await().atMost(Duration.ofSeconds(20)).untilAsserted(() -> {
            Mockito.verify(myService).doSomething("hello world");
        });

        await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
            String queueUrl = amazonSQS.getQueueUrl(QUEUE_NAME).getQueueUrl();
            List<Message> remainingMessages = amazonSQS.receiveMessage(queueUrl).getMessages();
            Assertions.assertTrue(remainingMessages.isEmpty(), "Queue should be empty after processing");
        });
    }
}

Let me know if there is a cleaner solution

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.