Scaffeine: как установить другое время истечения срока действия для значения по умолчанию

#scala #caching #caffeine-cache

Вопрос:

Пример использования приложения Scala:

У нас есть основанный на Scala модуль, который считывает данные из глобального кэша (Redis) и сохраняет их в локальном кэше(Scaffeine). Поскольку мы хотим, чтобы эти данные обновлялись асинхронно, мы используем LoadingCache с длительностью обновления, установленной для окна обновления 2 секунды.

Вопрос:

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

например, если ключ отсутствует в глобальном кэше, мы хотим сохранить тот же ключ в локальном кэше со значением по умолчанию и окном обновления, установленным на 5 минут. Если ключ присутствует в глобальном кэше, мы хотим сохранить его в локальном кэше с фактическим значением и окном обновления, установленным на 30 минут.

Пример кода

 object LocalCache extends App {

  // data being stored in the cache
  class DataObject(data: String) {
    override def toString: String = {
      "[ 'data': '"   this.data   "' ]"
    }
  }

  // loader helper
  private def loaderHelper(key: Int): Future[DataObject] = { 
    // this method will replace to read the data from Redis Cache
    // for now, returns different values per key

    if (key == 1) Future.successful(new DataObject("LOADER_HELPER_1"))
    else if (key == 2) Future.successful(new DataObject("LOADER_HELPER_2"))
    else Future.successful(new DataObject("LOADER_HELPER"))
  }

  // async loader
  private def loader(key: Int): DataObject = {
      Try {
        Await.result(loaderHelper(key), 1.seconds)
      } match {
        case Success(result) =>
          result
        case Failure(exception: Exception) =>
          val temp: DataObject = new DataObject("LOADER")
          temp
      }
  }

  // initCache
  private def initCache(maximumSize: Int): LoadingCache[Int, DataObject] =
    Scaffeine()
      .recordStats()
      .expireAfterWrite(2.second)
      .maximumSize(maximumSize)
      .build(loader)

  // operations on the cache.
  val cache: LoadingCache[Int, DataObject] = initCache(maximumSize = 500)
  cache.put(1, new DataObject("foo"))
  cache.put(2, new DataObject("hoo"))

  println("sleeping for 3 secn")
  Thread.sleep(3000)
  println(cache.getIfPresent(1).toString)
  println(cache.getIfPresent(2).toString)
  println(cache.get(3).toString)

  println("sleeping for 10 secn")
  Thread.sleep(10000)
  println("waking up from 10 sec sleep")

  println(cache.get(1).toString)
  println(cache.get(2).toString)
  println(cache.get(3).toString)

  println("nCache Stats: "  cache.stats())
}

 

Я вижу множество пользовательских политик.policy, которые можно использовать для перезаписи политик expiryAfter (expiryAfterWrite/Обновление/Доступ), но ничего нельзя найти для политик refreshAterWrite, которые асинхронно обновляют данные. Любая помощь будет ощутима.

P.S. Я очень новичок в работе над Scala, а также в изучении лесов.

Ответ №1:

К сожалению, обновление переменных пока не поддерживается. Существует открытая проблема, связанная с предоставлением этой функции.

На данный момент срок действия может быть настраиваемым для каждой записи, но автоматическое обновление исправлено. Обновление вручную может быть вызвано LoadingCache.refresh(key) , если вы хотите управлять им самостоятельно. Например, вы можете периодически перебирать записи (через asMap() представление) и обновлять их вручную на основе пользовательских критериев.

Кэш AsyncLoadingCache может быть полезен вместо блокировки в будущем в вашем загрузчике кэша. Кэш вернет будущее в полете, не сделает его пригодным для использования до тех пор, пока значение не материализуется, и удалит его в случае сбоя. Обратите внимание, что synchronous() представление очень полезно для асинхронных кэшей для доступа к большему количеству операций.

После тестирования вы можете обнаружить, что поддельный тикер Гуавы полезен для имитации времени.

Комментарии:

1. Спасибо @Ben за помощь.