Как установить срок действия/TTL (время жизни) для документов Couchbase, используя Spring-boot-starter-data-couchbase и Spring-Boot-Starter-Cache?

Я работаю над микросервисом поставщика OTP (одноразовых паролей) и хочу кэшировать OTP в Couchbase и получать их по заданному ключу. Я могу добиться этого, используя следующие фрагменты кода. Но я не могу реализовать одну последнюю функцию: OTP должен быть кратковременным и автоматически удаляться из кеша через определенный настраиваемый интервал.

Я использую следующие зависимости -

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-couchbase</artifactId>
        </dependency>

и я настроил CacheConfig следующим образом:

@Configuration
public class CacheConfig {

    @Value("${couchbase.url}")
    private String url;

    @Value("${couchbase.username}")
    private String username;

    @Value("${couchbase.password}")
    private String password;

    @Value("${couchbase.bucket}")
    private String bucket;

    public static final String CACHE_NAME  = "otp-cache";

    @Bean(destroyMethod = "disconnect")
    public Cluster cluster() {
        return Cluster.connect(url, username, password);
    }

    @Bean
    public CacheManager cacheManager() {
        return CouchbaseCacheManager.create(new SimpleCouchbaseClientFactory(cluster(), bucket, null));
    }
}

наконец, в моем классе обслуживания, где я генерирую OTP, я использую аннотацию @Cacheable следующим образом:

@Cacheable(cacheNames = CacheConfig.CACHE_NAME, key = "'provider_'+#key")
    @Override
    public Integer generateOTP(String key) {
        StringBuilder generatedOTP = new StringBuilder();
        SecureRandom secureRandom = new SecureRandom();
        LOGGER.info("generating OTP for provider(not from cache) - "+key);
        try {
            secureRandom = SecureRandom.getInstance(secureRandom.getAlgorithm());
            for (int i = 0; i < LENGTH_OF_OTP; i++) {
                generatedOTP.append(secureRandom.nextInt(9));
            }
        } catch (NoSuchAlgorithmException e) {
            LOGGER.error("exception occurred in generating OTP");
        }
        return Integer.parseInt(generatedOTP.toString());
    }

Я встречал некоторые решения, которые предлагают использовать аннотацию @CacheEvict с методом @Scheduled, но при этом будет очищен весь кеш, а не только записи с истекшим сроком действия. Я также попытался обернуть ответ метода @Cacheable в сериализуемый объект и использовал аннотацию @Document(expiryExpression = и @Expiry, но это тоже не работает, кроме того, я получаю исключение приведения класса, когда объект извлекается из кеш и Spring пытаются десериализовать его в класс pojo.

Я также вижу это свойство, используя автоматическое предложение моей IDE в файле свойств приложения Spring.cache.couchbase.expiration=, но это тоже не работает.

Как установить срок действия для каждого OTP, кэшированного в сегменте Couchbase?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
0
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Из некоторых ссылок получено, что Spring @Cachebale не поддерживает срок действия (https://stackoverflow.com/a/29191001/11259999), поэтому полностью удален механизм кэширования Spring (удалена зависимость Spring-boot-starter-cache сам) и заменил его явными вызовами Couchbase для чтения/удаления объектов из кеша.

вот изменения в реализации

  1. создал POJO для сохранения OTP в корзине Couchbase
@Setter
@Getter
@AllArgsConstructor
public class OTP implements Serializable {
    String providerId;
    int otp;


}
  1. изменения в Сервисе -
 @Autowired
    CacheConfig cacheConfig;

 public Integer getOrGenerateOTP(String key) {
        try {
            Cluster cluster = cacheConfig.cluster();
            if (cluster.bucket(cacheConfig.getBucket()).defaultCollection().exists(key).exists()) {
                GetResult getResult = cluster.bucket(cacheConfig.getBucket()).defaultCollection().get(key);
                if (getResult.contentAsObject().containsKey("otp"))
                    return Integer.parseInt("" + getResult.contentAsObject().get("otp"));
            } else {
                StringBuilder generatedOTP = new StringBuilder();
                SecureRandom secureRandom = new SecureRandom();
                LOGGER.info("generating OTP for provider(not from cache) - " + key);
                try {
                    secureRandom = SecureRandom.getInstance(secureRandom.getAlgorithm());
                    for (int i = 0; i < LENGTH_OF_OTP; i++) {
                        generatedOTP.append(secureRandom.nextInt(9));
                    }
                } catch (NoSuchAlgorithmException ex) {
                    LOGGER.error("exception occurred in generating OTP");
                }
               
                Temporal startTm = Instant.now();
                Temporal endTm = Instant.now().plus(Period.ofDays(2));
                Duration d= Duration.ofSeconds(10); // can be used in place of Duration.between(startTm, endTm)
                cluster.bucket(cacheConfig.getBucket())
                        .defaultCollection()
                        .upsert(key, new OTP(key, Integer.parseInt(generatedOTP.toString())),
                                UpsertOptions.upsertOptions().expiry(d));


                return Integer.parseInt(generatedOTP.toString());
            }
        } catch (Exception e) {
            LOGGER.error(e.getStackTrace());
        }
        return null;
    }

 public void clearOtp(String key) {
        try {
            Cluster cluster = cacheConfig.cluster();
            GetResult getResult = cluster.bucket(cacheConfig.getBucket()).defaultCollection().get(key);
            cluster.bucket(cacheConfig.getBucket()).defaultCollection().remove(key);
        } catch (Exception e) {
            LOGGER.error(e.getStackTrace());
        }

    }

Это решение работает и служит моей цели, но если у кого-то есть обходной путь, который работает вместе с механизмом кэширования Spring, добавьте также сюда ответ. Кроме того, я не уверен, насколько производительность этих двух подходов соотносится друг с другом, поэтому любой ответ, разъясняющий это, также приветствуется.

Ответ принят как подходящий

Для продолжительности жизни 60 минут используйте

CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry(Duration.ofMinutes(60))

https://docs.spring.io/spring-data/couchbase/reference/couchbase/caching.html

принимая этот ответ, поскольку он больше соответствует моему первоначальному вопросу. сохраняю и мой ответ, так как он также решает ту же проблему, хотя и с другим подходом

soumitra goswami 04.06.2024 11:58

вот обновленный код компонента CacheManager, который работает с моим решением: ``` @Bean public CacheManager cacheManager() { CouchbaseCacheManager.CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.CouchbaseCacheManagerBuilder .fromConnectionFactory(new SimpleCouchbaseClientFactory(cluster(), Bucket, null)); builder.withCacheConfiguration(CACHE_NAME, CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry‌​(Duration.ofSeconds(‌​expiryInSec))); вернуть builder.build(); } ```

soumitra goswami 04.06.2024 12:00

Другие вопросы по теме