spring-bootdockerspring-cloudamazon-sqslocalstack

How to configure SQS endpoint via environment variable in Spring Boot?


I have a Spring Boot project that uses SQS queues. For local testing, I’m using a Docker container with LocalStack. To make the connection between my project and LocalStack work, the only way I found is by overriding the SQS endpoint directly in the configuration class, as shown below:

@Configuration
public class SQSClientConfig {

    @Bean
    public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory() {
        return SqsMessageListenerContainerFactory
                .builder()
                .sqsAsyncClient(sqsAsyncClient())
                .build();
    }

    @Bean
    public SqsAsyncClient sqsAsyncClient() {
        var credentials = EnvironmentVariableCredentialsProvider.create();
        return SqsAsyncClient.builder()
                .credentialsProvider(credentials)
                .endpointOverride(URI.create("http://localhost:4566")) *HERE*
                .region(DefaultAwsRegionProviderChain.builder()
                        .build().getRegion())
                .build();
    }

    @Bean
    public Listener listener() {
        return new Listener();
    }
}

However, since my project also runs in a container on AWS, I don’t want to remove this line every time I deploy it in AWS. Is there a way to override the SQS endpoint using environment variables instead? I have tried many environment variables and config properties, but the connection always falls back to the default URL (sqs.us-east-2.amazonaws.com).

Any suggestions on how to solve this would be greatly appreciated!


Solution

  • I would suggest the following approach:
    In your config file, e.g. application.yml, define the following key-value pair

    sqs_endpoint: ${SQS_ENDPOINT:}
    

    In the file from your example, change definition of SqsAsyncClient to the following:

    @Bean
    public SqsAsyncClient sqsAsyncClient(@Value("${sqs_endpoint}") String sqsEndpoint) {
        var credentials = EnvironmentVariableCredentialsProvider.create();
        var builder = SqsAsyncClient.builder();
        var isSqsEndpointPassed = sqsEndpoint != null && !sqsEndpoint.trim().isEmpty();
        if (isSqsEndpointPassed) {
                builder.endpointOverride(URI.create(sqsEndpoint))
        }
        return builder
                .credentialsProvider(credentials)
                .region(DefaultAwsRegionProviderChain.builder()
                        .build().getRegion())
                .build();
    }
    

    When you run your application locally pass environment variable
    java -jar app.jar -DSQS_ENDPOINT=http://localhost:4566

    Another common approach is to have 2 active profiles - default and local.
    Define the default configurations in application.yml and the local configurations in application-local.yml.
    And when you run your application locally, pass the active profile using the following key -Dspring.profiles.active=local