Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceInfoPropertySourceAdapter disables RabbitAutoConfiguration #36

Closed
pavax opened this issue Feb 1, 2018 · 4 comments
Closed

ServiceInfoPropertySourceAdapter disables RabbitAutoConfiguration #36

pavax opened this issue Feb 1, 2018 · 4 comments

Comments

@pavax
Copy link

pavax commented Feb 1, 2018

The ServiceInfoPropertySourceAdapter.java 'silently' disables the RabbitAutoConfiguration since SCS 1.5+

I created a sample project: https://github.com/pavax/cloudfoundry-sample

deploy it and go to the /management/env Actuator Endpoint (username: root / password: secret)

you'll find

springCloudServicesRabbitAutoconfigExcluder: {
spring.autoconfigure.exclude: "org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration"
},

Is this really intended? IMHO: It is kinda "harsh" to disable a AutoConfigiration completely. Since in many project we depend on the classes provided by Spring Boots' AutoConfigurations. In this particular case several beans are expecting a RabbitTemplate and even more everything done and exposed in the RabbitAnnotationDrivenConfiguration such as the SimpleRabbitListenerContainerFactory.

Funny Fact: No exception is beeing raised if you app is simply trying to listen to Rabbit Messages since the RabbitListener are not triggered at all (due to the missing @EnableRabbit annotation that is exposed for you in the RabbitAutoConfiguration -> RabbitAnnotationDrivenConfiguration. Kinda nasty to find these kind of bugs :)

@RabbitListener(queues = "my-queue")
public void processMyMessage(Message message) {
	
}

Note:
This Bug was already mentioned here: pivotal-cf/spring-cloud-services-starters#15 but since it's root-cause has nothing to do with the 'spring-cloud-services-starters' I thought I give it a try and create it this repository.

@scottfrederick
Copy link
Member

@pavax Here's the reason this is being done in the SCS Connectors:

When a project includes the SCS starters, it gets spring-amqp/spring-rabbitmq transitively for the circuit breaker service's Hystrix Streams support. This will cause Spring Boot to try to auto-configure a RabbitMQ connection.

The RabbitMQ connection info for the SCS circuit breaker is wrapped in the service binding in such a way that an app doesn't see it as raw RabbitMQ connection info, but the SCS Connector code for circuit breaker knows to look inside this wrapper to get the RMQ connection info. Since Boot auto-configuration doesn't see any RabbitMQ connection info, it defaults to localhost and sets up an RMQ connection accordingly. Since there typically isn't an RMQ on localhost, the RMQ health actuator reports DOWN.

So the short story was: add SCS starters to your app, your app's health actuator reports DOWN.

Our fix for this was to conditionally disable RMQ auto-configuration when it appears that the application isn't configuring its own RMQ connection info (such that Boot auto-configuration default of localhost would get applied).

This is a bit convoluted (and hard to explain), but we were trying to optimize for the case where an app using SCS doesn't have its own RMQ connection, while still allowing for the case where an app does have its own RMQ connection.

In your sample app you've configured RMQ connection info in application-local.yml, which should result in the SCS Connectors not disabling RMQ auto-configuration in that profile. In the cloud profile, if you've bound your app to an RMQ service instance then Spring Cloud Connectors will create the RMQ connection, which overrides Boot auto-configuration. So I'm not sure why this isn't working the way you'd expect it to.

@pavax
Copy link
Author

pavax commented Feb 1, 2018

@scottfrederick thanks four you answer.

the application-local.yml is only used for local dev on my machine - SCS should not even know about that since the 'local' profile is NOT active.

My main problem is, that the RabbitMQAutoConfiguration is disabled -> thus there is no RabbitTemplate configured for my application (see TestController the /api/test).

Secondly there is also no SimpleRabbitListenerContainerFactory configured due to the fact, that RabbitAnnotationDrivenConfiguration.java is imported by RabbitMQAutoConfiguration => My Listeners are not working (I omitted that part the example app)

yes there is a RabbitConnectionFactory configured by org.springframework.cloud.service.messaging.RabbitConnectionFactoryCreator but the other beans from RabbitMQAutoConfiguration are still misssing....

Have a look at TestController change the @Autowired field of RabbitTemplate from required to true [default] -> start the Application again -> exception since there is no bean.

Field rabbitTemplate in com.mimacom.samples.cloudfoundry.web.TestController required a bean of type 'org.springframework.amqp.rabbit.core.RabbitTemplate' that could not be found.

The only solution is, that I'd define my own rabbitTemplate bean, and my own rabbitListenerContainerFactory bean (basically I'd have to copy paste code from spring-boot) which IMHO is kinda unesthetic to do since there are spring-boot configurations taking care of that.
Note:
I also tried to define a spring.rabbitmq.host dummy variable (be it localhost or dummy.example.com) explicitly in my application-cloud.yml or bootstrap.yml (which should be loaded even earlier) in order to bypass the check at

private boolean appIsBoundToRabbitMQ() {
	return environment.containsProperty("spring.rabbitmq.host") &&
			!environment.getProperty("spring.rabbitmq.host").equals("localhost");
}

... but it still it always evaluates to false and thus disabled the RabbitMQAutoConfiguration

also I did update my example app to demonstrate this problem (please give it a try and deploy it to your pivotal cf instance)

BTW: would it be a solution for you guys to just disable the HealthIndicatorAutoConfiguration.RabbitHealthIndicatorConfiguration (eg disabling this class or by sneaking in the property management.health.rabbit.enabled=false) kinda ugly since a ConnectionFactory is still beeing created for localhost but never invoked. would be much more easier for my to copy-paste this code

@Bean
public HealthIndicator rabbitHealthIndicator() {
  return createHealthIndicator(this.rabbitTemplates);
}

... rather than to copy & paste the RabbitAutoConfiguration.RabbitTemplateConfiguration and RabbitAnnotationDrivenConfiguration

@spikymonkey
Copy link
Contributor

Hi @pavax, thanks very much for the investigation and sample app - both were really useful. I'm preparing a fix in #39. With this change, I can get your sample app started with no missing bean errors. If you have any feedback, please let us know!

@spikymonkey
Copy link
Contributor

#39 has been merged in - hopefully this resolves the issue. I'll mark this as closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants