0

I have Spring web application, and I need to create cache and put values there from database before I can allow any rest calls.

Query to db can be executed 8 minutes and I'm executing them using EventListener

@Override
@EventListener(ApplicationReadyEvent.class)
public void getValuesFromDB() {
    loaderService.getValuesFromDBToCache();
}

Problem that I need to do it when context created and Cache created, so I cannot do it in PostConstruct.

How to restrict receiving calls on endpoint while loaderService.getValuesFromDBToCache(); is working?

Bohdan Myslyvchuk
  • 1,183
  • 2
  • 10
  • 28

1 Answers1

1

I think this approach of not allowing API calls for 8 minutes is not a good approach. You should try and change it to lazy loading if its possible.

If you want to do it with some specific delay or up to the time when cache is done loading, one way is to intercept the calls with something like below given code,

public class SampleInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String theMethod = request.getMethod();

        if (checkIsCacheProcessingDone()) {

            return true;
        }
        else {
            //not allowed
            response.sendError(HttpStatus.METHOD_NOT_ALLOWED.value());
            return false;
        }
    }

private boolean checkIsCacheProcessingDone(){
//a boolean should be created in cache or where ever you prefer which is accessible from this context and check if that value is true or not
}

Now register it using below code,

@Configuration
public class SampleConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SampleInterceptor()).addPathPatterns(yourPath);
    }
}

This will definitely have some performance overheads since this will be processed for each and every API call whether the caching is done or not. I definitely will not proceed like this, rather I would do the lazy loading of cache at run time.

Do not go this route unless you are sure you want to block the user.

EDIT===============================================================

Another approach that came to my mind is, Create an application context without web, then populate the cache(I hope you are using external cache like redis etc and not in memory) and once its done that is, db reading is done restart the application. A sample would look like below code,

ConfigurableApplicationContext configurableApplicationContext = SpringApplicationBuilder(OmsBasketApiApplication.class).web(
                WebApplicationType.NONE).run(args);

try {
    addToredis(configurableApplicationContext);
} catch (Exception exception){
    //do something else? System.exit(1)?
} finally {
    configurableApplicationContext.close();
}

configurableApplicationContext = SpringApplicationBuilder(OmsBasketApiApplication.class).run(args);

Hope this helps

Nithin
  • 643
  • 3
  • 11
  • thank you very for your reply, the problem is that I need to use this cache i n every endpoint call. So I cannot apply Lazy, because then I will be waiting 8 minute in case I receive request. That is why I need to populate cache BEFORE. And check every request which will impact my perforamnce is also not the case I want. – Bohdan Myslyvchuk Apr 13 '20 at 17:55
  • I have added another way, does that solve your problem? – Nithin Apr 13 '20 at 18:22