I am working on a project in which a database is polled for events, if a valid event is detected then service activators are called downstream to get information about the event. Some processing is performed and then the result is written to back to the database.
What I am trying to achieve is in the case in which the database is down or any of the downstream services are unavailable then my microservice would pause polling for a configurable amount of time after which it would start again.
So far I have looked into CircuitBreakerAdvice and RetryAdvice but those seem to apply to service activators and not inbound channel adapters. I am also aware that Resilience4j provides a comprehensive circuit breaker mechanism but I have found no way to implement it into my project.
The solution that I have come up with is to implement a ReceiveMessageAdvice which sets the polling active and pass it to the poller. The error channel will keep track of the number of errors that have accumulated and when a configured threshold is reached it sets the pollingActive attribute to false. As for reactivating the polling I am a bit stuck. My guess would be scheduling a task to change value back to true after some time but am unsure of where or how to do it.
Polling Channel
@Bean
public IntegrationFlow readDBMessage() {
return IntegrationFLows.fromSupplier(
() -> dbService.readMessage(),
channelAdapter ->
channelAdapter.poller(
pollerSpec ->
pollerSpec.fixedDelay(
\\polling period)
.advice(messagePollingControlAdvice())
.channel("apiCallChannel")
.get();
}
MessagePollingControlAdvice
public static class MessagePollingControlAdvice implements ReceiveMessageAdvice {
private volatile boolean pollingActive = false;
@Override
public boolean beforeReceive(Object source) {
return pollingActive;
}
@Override
public Message<?> afterReceive(Message<?> result, Object source) {
return result;
}
public boolean isPollingActive() {
return pollingActive;
}
//call this method from whatever place in your code to activate/deactivate poller
public void setPollingActive(boolean pollingActive) {
this.pollingActive = pollingActive;
}
}
Taken from How to stop OR change delay of Spring Integration Poller
Any advice on how I should go on about doing this? Is there something that I am missing in the documentation?
UPDATE Thank you Artem!
I have implemented the suggestion that Artem has given. Below is the code for reference in case anyone else runs into this.
MessagePollingControlAdvice
public static class MessagePollingControlAdvice implements ReceiveMessageAdvice {
private volatile boolean pollingActive = false;
private volatile Long pollingDeactivatedTime = Instant.now().getEpochSecond();
@Override
public boolean beforeReceive(Object source) {
// Get the desired time from configuration file
if (!pollingActive && (Instant.now().getEpochSecond() - pollingDeactivatedTime) > 30) {
pollingActive = true;
}
return pollingActive;
}
@Override
public Message<?> afterReceive(Message<?> result, Object source) {
return result;
}
public boolean isPollingActive() {
return pollingActive;
}
//call this method from whatever place in your code to activate/deactivate poller
public void setPollingActive(boolean pollingActive) {
this.pollingDeactivatedTime = Instant.now().getEpochSecond();
this.pollingActive = pollingActive;
}
}
I have taken a look at SimpleActiveIdleReceiveMessageAdvice and will certainly implement some of the logic in my code as well.
As a follow up question: from what I understand the code inside the advice gets executed even when an error occurs during polling, so is it possible to keep track of errors in this class and extend the logic to deactivate polling from inside it?