Spring Boot 2.0.0.RC2 KafkaHealthIndicator, Actuator {“status”:“DOWN”} - spring

I ported my application from Spring Boot 2.0.0.M6 to Spring Boot 2.0.0.RC2 and ran into the issue with KafkaHealthIndicator that thinks right now, that my Kafka status is DOWN.
kafka":{
"status":"DOWN",
"details":{
"clusterId":"wpAKGc_DQBWy9YfPTLNctQ",
"brokerId":"0",
"nodes":1
}
}
org.springframework.boot.actuate.kafka.KafkaHealthIndicator uses the following logic in order to determine the status:
Status status = nodes >= replicationFactor ? Status.UP : Status.DOWN;
where replication factor is retrieved by the following property: transaction.state.log.replication.factor
I have added the following properties to my Kafka server.properties:
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
but it doesn't help.
What am I doing wrong and how to fix it ?
Right now, I use the temporal solution with disabling healthcheck for Kafka:
management.health.kafka.enabled=false
but I don't like it and I want to fix it.

This worked fine for me...
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
with
#SpringBootApplication
public class So48965775Application {
public static void main(String[] args) {
SpringApplication.run(So48965775Application.class, args);
}
#Bean
public ApplicationRunner runner(KafkaHealthIndicator health) {
return args -> {
Executors.newSingleThreadExecutor().execute(() -> {
while (true) {
System.out.println(health.health());
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
};
}
}
and
UP {clusterId=ZR4GdILXSFSIGI1wDiKNLg, brokerId=0, nodes=1}
Did you restart the broker after changing the properties?

Related

Kafka Consumer with Circuit Breaker, Retry Patterns using Resilience4j

I need some help in understanding how I can come up with a solution using Spring boot, Kafka, Resilence4J to achieve a microservice call from my Kafka Consumer. Let's say if the Microservice is down then I need to notify my Kafka consumer using a circuit breaker pattern to stop fetching the messages/events until the Microservice is up and running.
With Spring Kafka, you could use the pause and resume methods depending on the CircuitBreaker state transitions. The best way I found for this is to define it as "supervisor" with an #Configuration Annotation. Resilience4j is also used.
#Configuration
public class CircuitBreakerConsumerConfiguration {
public CircuitBreakerConsumerConfiguration(CircuitBreakerRegistry circuitBreakerRegistry, KafkaManager kafkaManager) {
circuitBreakerRegistry.circuitBreaker("yourCBName").getEventPublisher().onStateTransition(event -> {
switch (event.getStateTransition()) {
case CLOSED_TO_OPEN:
case CLOSED_TO_FORCED_OPEN:
case HALF_OPEN_TO_OPEN:
kafkaManager.pause();
break;
case OPEN_TO_HALF_OPEN:
case HALF_OPEN_TO_CLOSED:
case FORCED_OPEN_TO_CLOSED:
case FORCED_OPEN_TO_HALF_OPEN:
kafkaManager.resume();
break;
default:
throw new IllegalStateException("Unknown transition state: " + event.getStateTransition());
}
});
}
}
This is what I used in combination with a KafkaManager annotated with #Component.
#Component
public class KafkaManager {
private final KafkaListenerEndpointRegistry registry;
public KafkaManager(KafkaListenerEndpointRegistry registry) {
this.registry = registry;
}
public void pause() {
registry.getListenerContainers().forEach(MessageListenerContainer::pause);
}
public void resume() {
registry.getListenerContainers().forEach(MessageListenerContainer::resume);
}
}
In addition my consumer service looks like this:
#KafkaListener(topics = "#{'${topic.name}'}", concurrency = "1", id = "CBListener")
public void receive(final ConsumerRecord<String, ReplayData> replayData, Acknowledgment acknowledgment) throws
Exception {
try {
httpClientServiceCB.receiveHandleCircuitBreaker(replayData);
acknowledgement.acknowledge();
} catch (Exception e) {
acknowledgment.nack(1000);
}
}
And the #CircuitBreaker Annotation:
#CircuitBreaker(name = "yourCBName")
public void receiveHandleCircuitBreaker(ConsumerRecord<String, ReplayData> replayData) throws
Exception {
try {
String response = restTemplate.getForObject("http://localhost:8081/item", String.class);
} catch (Exception e ) {
// throwing the exception is needed to trigger the Circuit Breaker state change
throw new Exception();
}
}
And this is additionally supplemented by the following application.properties
resilience4j.circuitbreaker.instances.yourCBName.failure-rate-threshold=80
resilience4j.circuitbreaker.instances.yourCBName.sliding-window-type=COUNT_BASED
resilience4j.circuitbreaker.instances.yourCBName.sliding-window-size=5
resilience4j.circuitbreaker.instances.yourCBName.wait-duration-in-open-state=10000
resilience4j.circuitbreaker.instances.yourCBName.automatic-transition-from-open-to-half-open-enabled=true
spring.kafka.consumer.enable.auto.commit = false
spring.kafka.listener.ack-mode = MANUAL_IMMEDIATE
Also have a look at https://resilience4j.readme.io/docs/circuitbreaker
If you are using Spring Kafka, you could maybe use the pause and resume methods of the ConcurrentMessageListenerContainer class.
You can attach an EventListener to the CircuitBreaker which listens on state transitions and pauses or resumes processing of events. Inject the CircuitBreakerRegistry into you bean:
circuitBreakerRegistry.circuitBreaker("yourCBName").getEventPublisher().onStateTransition(
event -> {
switch (event.getStateTransition()) {
case CLOSED_TO_OPEN:
container.pause();
case OPEN_TO_HALF_OPEN:
container.resume();
case HALF_OPEN_TO_CLOSED:
container.resume();
case HALF_OPEN_TO_OPEN:
container.pause();
case CLOSED_TO_FORCED_OPEN:
container.pause();
case FORCED_OPEN_TO_CLOSED:
container.resume();
case FORCED_OPEN_TO_HALF_OPEN:
container.resume();
default:
}
}
);

Can not run few methods sequentially when Spring Boot starts

I have to run a few methods when Application starts, like the following:
#SpringBootApplication
public class Application implements CommandLineRunner {
private final MonitoringService monitoringService;
private final QrReaderServer qrReaderServer;
#Override
public void run(String... args) {
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
However, only the first one is executed! And the application is started:
... Started Application in 5.21 seconds (JVM running for 6.336)
... START_MONITORING for folder: D:\results
The second one is always skipped!
If change the call order - the only the second one will be executed.
Could not find any solution for launching both at the beginning - tried #PostConstruct, ApplicationRunner, #EventListener(ApplicationReadyEvent.class)...
Looks like they are blocking each other somehow. Despite the fact that both have void type.
Monitoring launch implementation:
#Override
public void launchMonitoring() {
log.info("START_MONITORING for folder: {}", monitoringProperties.getFolder());
try {
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == ENTRY_CREATE) {
log.info("FILE_CREATED: {}", event.context());
// some delay for fully file upload
Thread.sleep(monitoringProperties.getFrequency());
String fullFileName = getFileName(event);
String fileName = FilenameUtils.removeExtension(fullFileName);
processResource(fullFileName, fileName);
}
}
key.reset();
}
} catch (InterruptedException e) {
log.error("interrupted exception for monitoring service", e);
} catch (IOException e) {
log.error("io exception while processing file", e);
}
}
QR Reader start (launch TCP server with Netty configuration):
#Override
public void launchServer() {
try {
ChannelFuture serverChannelFuture = serverBootstrap.bind(hostAddress).sync();
log.info("Server is STARTED : port {}", hostAddress.getPort());
serverChannel = serverChannelFuture.channel().closeFuture().sync().channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
shutdownQuietly();
}
}
How to solve this issue?
Start launchMonitoring() asynchronously.
The easiest way to do this is to enable Async by adding #EnableAsync on your Application
and then annotate launchMonitoring() with #Async
Not sure if launchServer() should also be started asynchronously.
EDIT: completed Answer
No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
By default Spring will create a SimpleAsyncTaskExecutor, but you can provide your taskExecutor
Example:
#EnableAsync
#Configuration
public class AsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.set... // your custom configs
executor.initialize();
return executor;
}
...
}

How can I shutdown Spring boot thread pool project amicably which is 24x7 running

I have created spring boot thread pool project which has thread that needs to run 24x7 once spawned but when I need to stop the app in server for some maintenance it should shutdown after completing its current task and not taking up any new task.
My code for the same is:
Config class
#Configuration
public class ThreadConfig {
#Bean
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executorPool = new ThreadPoolTaskExecutor();
executorPool.setCorePoolSize(10);
executorPool.setMaxPoolSize(20);
executorPool.setQueueCapacity(10);
executorPool.setWaitForTasksToCompleteOnShutdown(true);
executorPool.setAwaitTerminationSeconds(60);
executorPool.initialize();
return executorPool;
}
}
Runnable class
#Component
#Scope("prototype")
public class DataMigration implements Runnable {
String name;
private boolean run=true;
public DataMigration(String name) {
this.name = name;
}
#Override
public void run() {
while(run){
System.out.println(Thread.currentThread().getName()+" Start Thread = "+name);
processCommand();
System.out.println(Thread.currentThread().getName()+" End Thread = "+name);
if(Thread.currentThread().isInterrupted()){
System.out.println("Thread Is Interrupted");
break;
}
}
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void shutdown(){
this.run = false;
}
}
Main class:
#SpringBootApplication
public class DataMigrationPocApplication implements CommandLineRunner{
#Autowired
private ThreadPoolTaskExecutor taskExecutor;
public static void main(String[] args) {
SpringApplication.run(DataMigrationPocApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
for(int i = 1; i<=20 ; i++){
taskExecutor.execute(new DataMigration("Task " + i));
}
for (;;) {
int count = taskExecutor.getActiveCount();
System.out.println("Active Threads : " + count);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 0) {
taskExecutor.shutdown();
break;
}
}
System.out.println("Finished all threads");
}
}
I need help to understand if I need to stop my spring boot application it should stop all the 20 threads running which runs (24x7) otherwise after completing there current loop in while loop and exit.
I would propose couple of changes in this code to resolve the problem
1) since in your POC processCommand calls Thread.sleep, when you shutdown the executor and it interrupts workers InterruptedException get called but is almost ignored in your code. After that there is if(Thread.currentThread().isInterrupted()) check which will return false for the reason above. Similar problem is outlined in the post below
how does thread.interrupt() sets the flag?
the following code change should fix the problem:
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
shutdown();
}
}
2) Also because of ThreadConfig::taskExecutor executorPool.setWaitForTasksToCompleteOnShutdown(true) Spring will call executor.shutdown instead of executor.shutdownNow. According to javadoc ExecutorService.shutdown
Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted.
So I would recommend to set
executorPool.setWaitForTasksToCompleteOnShutdown(false);
Other things to improve in this code: although DataMigration is annotated as a component the instances of this class are creared not by Spring. You should try using factory method similar to ThreadConfig::taskExecutor in order to make Spring initiate instances of DataMigration for example to inject other bean into DataMigration instances.
In order to shutdown executor when running jar file on linux environment you can for example add actuator module and enable shutdown endpoint:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
in application.properties:
endpoints.shutdown.enabled=true
It will enable JMX shutdown endpoint and you can call shutdown on it.
If you want current job cycle of the task to be finished you should set
executorPool.setWaitForTasksToCompleteOnShutdown(true);
In order to connect to your jvm process on linux env remotely you have to specify an RMI Registry port.
Here is a detailed article:
How to access Spring-boot JMX remotely
If you just need to connect to JMX from local env you can run jsoncole or command-line tools : Calling JMX MBean method from a shell script
Here is an example uf using one of these tools - jmxterm
$>run -d org.springframework.boot: -b org.springframework.boot:name=shutdownEndpoint,type=Endpoint shutdown
#calling operation shutdown of mbean org.springframework.boot:name=shutdownEndpoint,type=Endpoint with params []
#operation returns:
{
message = Shutting down, bye...;
}

AWS IoT MQTT Client with Apache camel-mqtt

I am looking into building a AWS IoT Java Client with Apache Camel ( using camel-mqtt ) + Spring Boot. It sounds like a good match to me, but couldn't find any examples. Is there any drawback that I can't see ? Would be interested to see any pointers.
I got it working with the below configuration. sslContext bean holds the certificate/security :
#Bean
RouteBuilder awsIoTRoute() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer://foo?repeatCount=0&delay=5000&fixedRate=true&period=17s")
.setBody(simple("TEST MESSAGE"))
.to("mqtt:awsIoTPublisher?host=ssl://{{aws.iot.host}}:8883&publishTopicName={{aws.iot.pub.topic}}&clientId={{aws.iot.pub.clientId}}&sslContext=#sslContext")
.log("Sent :"+body().convertToString().toString());
from("mqtt:awsIoTReciever?host=ssl://{{aws.iot.host}}:8883&subscribeTopicName={{aws.iot.sub.topic}}&clientId={{aws.iot.sub.clientId}}&sslContext=#sslContext").log("Recieved : "+body().convertToString());
}
};
}

spring reactor and boot dependency

Is boot a prerequisite to run spring reactor?
I am trying to use spring reactor in a regular web application environment. I can see that the reactor configuration is created. Consumers are registered. Notifications are called. Events are NOT fired. What and how to check?
Configuration
#Configuration
#EnableReactor
public class ReactorConfiguration {
#Bean
Environment env() {
return new Environment();
}
#Bean
Reactor createReactor(Environment env) {
return Reactors.reactor().env(env).dispatcher(Environment.THREAD_POOL)
.get();
}
}
Registering consumers:
#PostConstruct
public void onStartUp() {
logger.debug("Registering Consumers");
reactor.on(Selectors.T(Envelope.class), processParentRequest());
reactor.on(Selectors.T(Bundle.class), processOptimizerRequest());
reactor.on(Selectors.$(Constants.LOWER_ASG), processLowerAsgsRequest());
reactor.on(Selectors.$(constants.SET_CONSUMPTION_LEVEL),
processConsumersRequest());
reactor.on(Selectors.$(constants.SET_GENERATION_LEVEL),
processProducersRequest());
reactor.on(Selectors.$(constants.SET_STORAGE_SUPPLY_LEVEL),
processStoragesRequest());
}
private Consumer<Event<Envelope>> processParentRequest() {
return envelope -> optimizerUpdatingService
.processParentRequest(envelope);
}
private Consumer<Event<Bundle>> processOptimizerRequest() {
return bundle -> eventProcessingDispenser
.processOptimizerRequest(bundle);
}
private Consumer<Event<Envelope>> processLowerAsgsRequest() {
return envelope -> lowerAsgsProcessingService
.processLowerAsgRequest(envelope);
}
private Consumer<Event<Message>> processConsumersRequest() {
return message -> consumersProcessingService
.processConsumersRequest(message);
}
private Consumer<Event<Message>> processProducersRequest() {
return message -> producersProcessingService
.processProducersRequest(message);
}
private Consumer<Event<Message>> processStoragesRequest() {
return message -> storageProcessingService
.processStoragesRequest(message);
}
Spring Boot is not a pre-requisite at all, it simply provides some conveniences when using Spring with Reactor.
There could be any number of things happening. Without any details it's hard to give specific suggestions.
Simple answer is NO.
Spring boot is not a pre requisite but it makes your bootstrapping easy.
All you need is project reactor in your classpath to use reactor

Resources