How to config max-delivery-attempts for Spring Boot with Embedded ActiveMQ Artemis? - spring-boot

I would like to config the max-delivery-attempts of dead letter as described in the manual.
I tried Spring Boot with embedded ActiveMQ Artemis JMS server, but cannot figure out how to set max-delivery-attempts value.

After debugging the Configuration instance I finally find the method. Here's the code:
#Configuration
public class RedeliveryConfiguration implements ArtemisConfigurationCustomizer {
#Override
public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
Map<String, AddressSettings> addressesSettings = configuration.getAddressesSettings();
// # is the catch all address or default address
addressesSettings.get("#").setMaxDeliveryAttempts(2);
}
}

Related

How to enable IP lookup - enableLookups in Spring MVC

On Tomcat there is an attribute "enableLookups" to enable IP lookup. I have a program which we have migrated from Tomcat to Spring MVC and I am not getting any idea where can I set this atrribute.
#RequestMapping(method = RequestMethod.GET, path = "/something")
public String something(Model model, HttpServletRequest request) {
String someVar = request.getRemoteHost();
.....
.......
request.getRemoteHost() - returns IP Address instead of host name.
If your Spring Boot application is configured to use an embedded application server, use the WebServerFactoryCustomizer facility to configure the server according to your needs. Some hints specific to Tomcat as embedded server are given in the official Spring Boot guide:
#Component
public class TomcatServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
#Override public void customize(TomcatServletWebServerFactory tomcatServletWebServerFactory) {
TomcatConnectorCustomizer customizer = connector -> connector.setEnableLookups(true);
tomcatServletWebServerFactory.addConnectorCustomizers(customizer);
}
}
Note, TomcatServletWebServerFactory is available since Spring Boot 2.0.0.

Report Metrics from Kafka to Actuator

I'm trying to get some metrics (client lag, ...) from kafka to provide it for consumption by prometheus.
My approach would be to write a simple springboot application which exposes the metrics for prometheus. I understand that kafka provides metrics to all its consumers via the interface MetricsReporter.
So I implemented a class which should do exactly that:
public class MonitoringIntegration implements MetricsReporter {
#Override
public void init(List<KafkaMetric> list) {
System.out.println("init");
for (KafkaMetric kafkaMetric : list) {
System.out.println(kafkaMetric.metricName());
System.out.println(kafkaMetric.metricValue());
}
}
#Override
public void metricChange(KafkaMetric kafkaMetric) {
System.out.println("Metric Change");
System.out.println(kafkaMetric.metricName());
System.out.println(kafkaMetric.metricValue());
}
#Override
public void metricRemoval(KafkaMetric kafkaMetric) {
System.out.println("Removal");
System.out.println(kafkaMetric.metricName());
System.out.println(kafkaMetric.metricValue());
}
#Override
public void close() {
System.out.println("close");
}
#Override
public void configure(Map<String, ?> map) {
System.out.println("Configuring");
System.out.println(map);
}
}
I registered this class with a bean:
#Configuration
public class MetricConfiguration {
#Bean
public ProducerFactory<?, ?> kafkaProducerFactory(KafkaProperties properties) {
Map<String, Object> producerProperties = properties.buildProducerProperties();
producerProperties.put(CommonClientConfigs.METRIC_REPORTER_CLASSES_CONFIG,
MonitoringIntegration.class.getName());
return new DefaultKafkaProducerFactory<>(producerProperties);
}
#Bean
public ConsumerFactory<?, ?> kafkaConsumerFactory(KafkaProperties properties) {
Map<String, Object> consumererProperties = properties.buildConsumerProperties();
consumererProperties.put(CommonClientConfigs.METRIC_REPORTER_CLASSES_CONFIG,
MonitoringIntegration.class.getName());
return new DefaultKafkaConsumerFactory<>(consumererProperties);
}
}
When I start the application some metrics will be printed out to cmd, but they have all default values (0.0, infinite, ..) and they will only be provided once after the application started.
Why am I not getting the metrics? What did I do wrong?
Cheers,
Fabian
Spring Kafka already exposes Kafka metrics as a JMX metrics. You dont need to update/send the metrics to Prometheus. Prometheus server will automatically read from your application's "/prometheus" endpoint. Enable Spring Actuator with Prometheus in your Spring project and configure the Prometheus server to read from it.
Here is a great example using Spring Boot - https://www.callicoder.com/spring-boot-actuator-metrics-monitoring-dashboard-prometheus-grafana/
MetricsReporter is not used to "report" metric values as they change. Check the docs. (For some reason I cant find the latest API).
https://archive.apache.org/dist/kafka/0.8.2-beta/java-doc/org/apache/kafka/common/metrics/MetricsReporter.html
A plugin interface to allow things to listen as new metrics are created so they can be reported.
metricChange() method will only be called when a metric is changed. This is the reason you see the first few outputs during application startup, because the metrics were created.
The consumer metrics support are only available on spring boot 2.1+ versions.
Auto-configuration Support For New Metrics
Metrics coverage has been improved to include:
Hibernate metrics
Spring Framework’s WebClient
Kafka consumer metrics
Log4j2 metrics
Jetty server thread pool metrics
Server-side Jersey HTTP request metrics
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes#auto-configuration-support-for-new-metrics
I recommend you to upgrade to newer versions. But if you really need to use Spring Boot prior versions, you can check my kafka metrics micrometer implementation at:
https://github.com/luiztoscano/spring-boot-kmetrics

Spring Cloud Config Client connecting to RabbitMQ

I have been trying to set up a Spring Cloud Config Server/Client. I have been following a few different examples (1, 2). I have the client and server set up correctly and can successfully query localhost:8888/localhost:8080 to see the values in JSON format.
My question is whether Spring Boot will automatically detect these properties provided by Spring Cloud Config Server. For now I am just attempting to connect to a RabbitMQ instance on startup but have had no success despite not having any errors. It does not connect to Rabbit or create the queues/exchanges.
It works when I have an application.properties file locally with the following properties but I wish to get these setting through Spring Cloud Config from a GitHub repository.
spring.rabbitmq.host=178.61.47.---
spring.rabbitmq.port=5672
spring.rabbitmq.username=mqtt
spring.rabbitmq.password=mqtt
I have looked through the questions here/issues on GitHub but can't see anything relating to this.
Code for client class is below:
#EnableAutoConfiguration
#ComponentScan
#SpringBootApplication
public class ConfigRabbitApplication {
final static String queueName = "arduino-weather-queue";
#Autowired
RabbitTemplate rabbitTemplate;
#Bean
Queue queue() {
return new Queue(queueName, true);
}
#Bean
Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("arduino-weather");
}
#Bean
TopicExchange exchange() {
return new TopicExchange("arduino-iot-exchange", true, false);
}
public static void main(String[] args) {
SpringApplication.run(ConfigRabbitApplication.class, args);
}
}
No, spring boot client is not aware that you want to fetch configuration from config-server. That is probably loaded when specific class in on a classpath, thats why you have to add org.springframework.cloud:spring-cloud-starter-config dependency. Its well described here: http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_client_side_usage
In case config-server is not on localhost:8888 you will also have to add:
spring.cloud.config.uri: http://myconfigserver.com
to your bootstrap.yml file ( its same as application.yml, just loaded earlier ).

How to change bitronix jms pool parameters?

I'm using Spring Boot 1.2.0.RC1 + bitronix + hornetq (embedded) + JPA, and I'd like to increase bitronix jmsConnectionFactory pool size, currently it's limited at 10. Is there a simple way to do it, inside application.properties for example or inside a #Configuration class?
You can't configure it via application.properties at the moment (I've opened an issue), but you can do it from a #Configuration class by declaring your own XAConnectionFactoryWrapper bean:
#Bean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new XAConnectionFactoryWrapper() {
#Override
public ConnectionFactory wrapConnectionFactory(
XAConnectionFactory connectionFactory) {
PoolingConnectionFactoryBean pool = new PoolingConnectionFactoryBean();
pool.setConnectionFactory(connectionFactory);
pool.setMaxPoolSize(50);
return pool;
}
};
}

Spring 4.1 #JmsListener configuration

I would like to use the new annotations and features provided in Spring 4.1 for an application that needs a JMS listener.
I've carefully read the notes in the Spring 4.1 JMS improvements post but I continue to miss the relationship between #JmsListener and maybe the DestinationResolver and how I would setup the application to indicate the proper Destination or Endpoint.
Here is the suggested use of #JmsListener
#Component
public class MyService {
#JmsListener(containerFactory = "myContainerFactory", destination = "myQueue")
public void processOrder(String data) { ... }
}
Now, I can't use this in my actual code because the "myQueue" needs to be read from a configuration file using Environment.getProperty().
I can setup an appropriate myContainerFactory with a DestinationResolver but mostly, it seems you would just use DynamicDestinationResolver if you don't need JNDI to lookup a queue in an app server and didn't need to do some custom reply logic. I'm simply trying to understand how Spring wants me to indicate the name of the queue in a parameterized fashion using the #JmsListener annotation.
Further down the blog post, I find a reference to this Configurer:
#Configuration
#EnableJms
public class AppConfig implements JmsListenerConfigurer {
#Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setDefaultContainerFactory(defaultContainerFactory());
SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
endpoint.setDestination("anotherQueue");
endpoint.setMessageListener(message -> {
// processing
});
registrar.registerEndpoint(endpoint);
}
Now, this makes some amount of sense and I could see where this would allow me to set a Destination at runtime from some external string, but this seems to be in conflict with using #JmsListener as it appears to be overriding the annotation in favor of endpoint.setMessageListener in the code above.
Any tips on how to specify the appropriate queue name using #JmsListener?
Also note that depending on use case you can already parameterize using properties file per environment and PropertySourcesPlaceholderConfigurer
#JmsListener(destinations = "${some.key}")
As per https://jira.spring.io/browse/SPR-12289
In case people are using #JmsListener with spring boot, you do not have to configure PropertySourcesPlaceholderConfigurer. It work's out the box
Sample:
class
#JmsListener(destination = "${spring.activemq.queue.name}")
public void receiveEntityMessage(final TextMessage message) {
// process stuff
}
}
application.properties
spring.activemq.queue.name=some.weird.queue.name.that.does.not.exist
Spring boot output
[26-Aug;15:07:53.475]-[INFO ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[931 ]-Successfully refreshed JMS Connection
[26-Aug;15:07:58.589]-[WARN ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[880 ]-Setup of JMS message listener invoker failed for destination 'some.weird.queue.name.that.does.not.exist' - trying to recover. Cause: User user is not authorized to read from some.weird.queue.name.that.does.not.exist
[26-Aug;15:07:59.787]-[INFO ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[931 ]-Successfully refreshed JMS Connection
[26-Aug;15:08:04.881]-[WARN ]-[,]-[DefaultMes]-[o.s.j.l.DefaultMessageListenerContainer ]-[880 ]-Setup of JMS message listener invoker failed for destination 'some.weird.queue.name.that.does.not.exist' - trying to recover. Cause: User user is not authorized to read from some.weird.queue.name.that.does.not.exist
This proves that #JmsListener is able to pickup property values from application.properties without actually setting up any explicit PropertySourcesPlaceholderConfigurer
I hope this helps!
You could eventually do that right now but it's a bit convoluted. You can set a custom JmsListenerEndpointRegistry using JmsListenerConfigurer
#Configuration
#EnableJms
public class AppConfig implements JmsListenerConfigurer {
#Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setEndpointRegistry(customRegistry());
}
}
and then override the registerListenerContainer method, something like
public void registerListenerContainer(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {
// resolve destination according to whatever -> resolvedDestination
((AbstractJmsListenerEndpoint)endpoint).setDestination(resolvedDestination);
super.registerListenerContainer(endpoint, factory);
}
But we could do better. Please watch/vote for SPR-12280

Resources