Reputation: 947
Before deploying our Spring Cloud microservices (packaged as Docker images) to AWS, we test them locally against LocalStack. As such, we have beans defined like the following in our code base that are autoconfigured:
@Bean("amazonKinesisAsyncMyBean")
@Primary
@Conditional(value = {LocalStackProfileCondition.class})
public AmazonKinesisAsync localAmazonKinesisAsync(
final LocalStackProfileProperties localStackProfileProperties,
final LocalStackProperties localStackProperties,
AWSCredentialsProvider awsCredentialsProvider) {
System.setProperty(SDKGlobalConfiguration.AWS_CBOR_DISABLE_SYSTEM_PROPERTY, "true");
System.setProperty(SDKGlobalConfiguration.DISABLE_CERT_CHECKING_SYSTEM_PROPERTY, "true");
return AmazonKinesisAsyncClientBuilder.standard()
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(
generateUriString(
localStackProperties.getProtocol().toLowerCase(),
localStackProperties.getHost(),
localStackProperties.getKinesis().getPort()),
localStackProfileProperties.getClient().getRegion()))
.withCredentials(awsCredentialsProvider)
.build();
}
With Spring Boot 2.3.5.RELEASE, Spring Cloud Hoxton.SR4, and Spring Cloud Stream Binder Kinesis 2.0.1.RELEASE, we are able to successfully test our Docker containers locally against LocalStack. However, after upgrading to Spring Cloud Hoxton.SR9 we are failing with the following stack trace:
Caused by: com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to squid.acme.com:8080 [squid.acme.com/x.x.x.x, squid.acme.com/x.x.x.x, squid.acme.com/x.x.x.x] failed: connect timed out
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleRetryableException(AmazonHttpClient.java:1207)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1153)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)
at com.amazonaws.services.kinesis.AmazonKinesisClient.doInvoke(AmazonKinesisClient.java:2809)
at com.amazonaws.services.kinesis.AmazonKinesisClient.invoke(AmazonKinesisClient.java:2776)
at com.amazonaws.services.kinesis.AmazonKinesisClient.invoke(AmazonKinesisClient.java:2765)
at com.amazonaws.services.kinesis.AmazonKinesisClient.executeDescribeStream(AmazonKinesisClient.java:875)
at com.amazonaws.services.kinesis.AmazonKinesisClient.describeStream(AmazonKinesisClient.java:846)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.createOrUpdate(KinesisStreamProvisioner.java:135)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.provisionProducerDestination(KinesisStreamProvisioner.java:91)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.provisionProducerDestination(KinesisStreamProvisioner.java:57)
at org.springframework.cloud.stream.binder.AbstractMessageChannelBinder.doBindProducer(AbstractMessageChannelBinder.java:223)
... 33 common frames omitted
Our local development environment is walled off from the internet, thus the connection timeout via the proxy. Regardless, the problem in the first place is that after upgrading Spring Cloud it appears the Kinesis binder is trying to connect to AWS to get the shard list. How can I ensure that these requests get routed to LocalStack and not AWS when I am running with the new configuration?
UPDATE 1:
After updating Spring Cloud Stream Kinesis Binder to 2.0.3.RELEASE, following is the stack trace I now receive:
Caused by: com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to squid.acme.com:8080 [squid.acme.com/x.x.x.x, squid.acme.com/x.x.x.x, squid.acme.com/x.x.x.x] failed: connect timed out
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleRetryableException(AmazonHttpClient.java:1207)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1153)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)
at com.amazonaws.services.kinesis.AmazonKinesisClient.doInvoke(AmazonKinesisClient.java:2809)
at com.amazonaws.services.kinesis.AmazonKinesisClient.invoke(AmazonKinesisClient.java:2776)
at com.amazonaws.services.kinesis.AmazonKinesisClient.invoke(AmazonKinesisClient.java:2765)
at com.amazonaws.services.kinesis.AmazonKinesisClient.executeListShards(AmazonKinesisClient.java:1557)
at com.amazonaws.services.kinesis.AmazonKinesisClient.listShards(AmazonKinesisClient.java:1528)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.getShardList(KinesisStreamProvisioner.java:141)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.getShardList(KinesisStreamProvisioner.java:122)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.createOrUpdate(KinesisStreamProvisioner.java:167)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.provisionProducerDestination(KinesisStreamProvisioner.java:93)
at org.springframework.cloud.stream.binder.kinesis.provisioning.KinesisStreamProvisioner.provisionProducerDestination(KinesisStreamProvisioner.java:59)
at org.springframework.cloud.stream.binder.AbstractMessageChannelBinder.doBindProducer(AbstractMessageChannelBinder.java:223)
... 33 common frames omitted
UPDATE 2:
After setting org.springframework
logging level to DEBUG
, I was able to capture the following Conditions Evaluation Report:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
ContextCredentialsAutoConfiguration matched:
- @ConditionalOnClass found required class 'com.amazonaws.auth.AWSCredentialsProvider' (OnClassCondition)
KinesisBinderConfiguration matched:
- @ConditionalOnMissingBean (types: org.springframework.cloud.stream.binder.Binder; SearchStrategy: all) did not find any beans (OnBeanCondition)
KinesisBinderConfiguration#dynamoDBStreams matched:
- @ConditionalOnMissingBean (types: com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreams; SearchStrategy: all) did not find any beans (OnBeanCondition)
KinesisBinderConfiguration.KinesisBinderHealthIndicatorConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.boot.actuate.health.HealthIndicator' (OnClassCondition)
- @ConditionalOnEnabledHealthIndicator management.health.defaults.enabled is considered true (OnEnabledHealthIndicatorCondition)
KinesisBinderConfiguration.KinesisBinderHealthIndicatorConfiguration#kinesisBinderHealthIndicator matched:
- @ConditionalOnMissingBean (names: kinesisBinderHealthIndicator; SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches:
-----------------
KinesisBinderConfiguration#amazonKinesis:
Did not match:
- @ConditionalOnMissingBean (types: com.amazonaws.services.kinesis.AmazonKinesisAsync; SearchStrategy: all) found beans of type 'com.amazonaws.services.kinesis.AmazonKinesisAsync' amazonKinesisAsyncMyBean (OnBeanCondition)
KinesisBinderConfiguration#cloudWatch:
Did not match:
- @ConditionalOnMissingBean (types: com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync; SearchStrategy: all) found beans of type 'com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync' amazonCloudWatchAsync (OnBeanCondition)
Matched:
- @ConditionalOnProperty (spring.cloud.stream.kinesis.binder.kpl-kcl-enabled) matched (OnPropertyCondition)
KinesisBinderConfiguration#dynamoDB:
Did not match:
- @ConditionalOnMissingBean (types: com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync; SearchStrategy: all) found beans of type 'com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync' amazonDynamoDBAsync (OnBeanCondition)
KinesisBinderConfiguration#dynamoDBLockRegistry:
Did not match:
- @ConditionalOnProperty (spring.cloud.stream.kinesis.binder.kpl-kcl-enabled=false) found different value in property 'spring.cloud.stream.kinesis.binder.kpl-kcl-enabled' (OnPropertyCondition)
KinesisBinderConfiguration#kinesisCheckpointStore:
Did not match:
- @ConditionalOnProperty (spring.cloud.stream.kinesis.binder.kpl-kcl-enabled=false) found different value in property 'spring.cloud.stream.kinesis.binder.kpl-kcl-enabled' (OnPropertyCondition)
KinesisBinderConfiguration#kinesisProducerConfiguration:
Did not match:
- @ConditionalOnMissingBean (types: com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration; SearchStrategy: all) found beans of type 'com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration' kinesisProducerConfiguration (OnBeanCondition)
Matched:
- @ConditionalOnProperty (spring.cloud.stream.kinesis.binder.kpl-kcl-enabled) matched (OnPropertyCondition)
Exclusions:
-----------
None
Unconditional classes:
----------------------
None
Upvotes: 1
Views: 518
Reputation: 121560
Let's look into that condition one more time:
KinesisBinderConfiguration#amazonKinesis:
Did not match:
- @ConditionalOnMissingBean (types: com.amazonaws.services.kinesis.AmazonKinesisAsync; SearchStrategy: all) found beans of type 'com.amazonaws.services.kinesis.AmazonKinesisAsync' amazonKinesisAsync (OnBeanCondition)
Pay attention to the amazonKinesisAsync
bean name. Doesn't look like it belongs to the mentioned localAmazonKinesisAsync
bean in your configuration. Probably your conditions doesn't work somehow and another AmazonKinesisAsync
bean wins which already points to the squid.acme.com:8080
endpoint...
Upvotes: 1