javaspringspring-bootredistimer

Springboot method timer


I have a usecase to track execution time of a method in springboot. If execution time exceeds the specific time then I need to throw an exception. I am looking for options to handle that in java and springboot. The method has interaction with redis cache something like mentioned below. Also the important aspect of this usecase is that exception should be thrown without any error in the calling method but purely based on execution time without capturing end time.

public CacheResponse getValue(String key) {
        try{
            return  redisJedisTemplate.opsForValue().get(key);
        } catch(Exception e){
            LOGGER.error("{}: Error fetching data with key {} {}", className,key,e.getMessage());
            return null;
        }
    }

Solution

  • You should use CompletableFuture with Executor service, in this case:

    Here is an example code below :

    import java.util.concurrent.*;
    
    public class TimeoutWrapper {
    
    private static final long MAX_EXECUTION_TIME = 1000; // in milliseconds
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    
    public <T> T executeWithTimeout(Callable<T> task) throws ExecutionTimeExceededException {
        Future<T> future = executor.submit(task);
        try {
            return future.get(MAX_EXECUTION_TIME, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            future.cancel(true);
            throw new ExecutionTimeExceededException("Method execution exceeded the maximum allowed time of " + MAX_EXECUTION_TIME + " ms");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    }
    

    With

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    @Service
    public class CacheService {
    
    @Autowired
    private RedisTemplate<String, CacheResponse> redisJedisTemplate;
    
    private final TimeoutWrapper timeoutWrapper = new TimeoutWrapper();
    
    public CacheResponse getValue(String key) {
        try {
            return timeoutWrapper.executeWithTimeout(() -> redisJedisTemplate.opsForValue().get(key));
        } catch (ExecutionTimeExceededException e) {
            LOGGER.error("{}: Execution time exceeded for key {} {}", className, key, e.getMessage());
            return null;
        } catch (Exception e) {
            LOGGER.error("{}: Error fetching data with key {} {}", className, key, e.getMessage());
            return null;
        }
    }