Условное запоминание в гуаве - PullRequest
1 голос
/ 07 октября 2019

Я знаю, как запомнить один объект . Тем не менее, я хотел бы отметить, только если выполняется какое-то условие. Я звоню в службу, которая иногда возвращает неуспешный ответ. Я хотел бы отметить, только если ответ службы в случае успеха.

MyResponse myResponse = myService.call()
boolean success = myResponse.isSuccessful();

И мой кеш создается так:

private Supplier<MyResponse> cache;

private void createCache() {
    this.cache = Suppliers
        .memoizeWithExpiration(myService::call, timeout,
            TimeUnit.MINUTES);
}

Вопрос: Можно ли каким-либо образом кешировать ответ только в том случае, если ответ был успешным с использованием поставщика, переданного методу memoizeWithExpiration?


Единственный обходной путьЯ обнаружил, что это делается для того, чтобы при получении значения сначала вызвать cache.get(), проверить, успешно ли хранится в кэше объект, а если нет, снова вызвать createCache(), чтобы очистить его, а затем снова получить значение. Таким образом, если последующий вызов службы вернет действительный объект, он будет сохранен, а если нет, каждый последующий вызов очистит кэш и снова вызовет службу.

 public MyResponse getResponse() {
    MyResponse myResponse = cache.get();
    if (myResponse.isSuccess()) {
      return myResponse;
    } else {
      createCache();
      return cache.get();
    }
  }

Однако в этом решении, есликэш-память пуста, и служба возвращает неуспешный ответ, она немедленно будет вызвана снова.

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Может ли это быть тем, что вы ищете?


    private void createCache() {
        this.cache = Suppliers.memoizeWithExpiration(
           Suppliers.compose(
               response -> (response.isSuccess() ? response : null),
               myService::call
           ),
           timeout,
           TimeUnit.MINUTES
        );
    }

Здесь он будет кэшировать ответ или ноль, в зависимости от того, был ли он успешным.

Подробнее о compose здесь https://github.com/google/guava/blob/master/guava/src/com/google/common/base/Suppliers.java#L45

РЕДАКТИРОВАТЬ : если вам нужно кэшировать значение при успехе и оставить кэш пустым при сбое, возвращая неудавшийся запрос, то вы почти там сами,просто немного измените логику возврата в getResponse, например:


    public MyResponse getResponse() {
        final MyResponse myResponse = cache.get();
        if (!myResponse.isSuccess()) {
            this.createCache(); // clear cache
        }
        return myResponse; // don't call .get() again!
    }

1 голос
/ 11 октября 2019

Вы можете создать метод callUntilSuccess в классе обслуживания или в любом другом подходящем месте (здесь я предполагаю, что он находится в вашей службе). Вы также можете определить максимальное количество попыток в этом методе, и после этого он вернет значение null, поэтому вы можете избежать бесконечного вызова вашей службы (это предложение не реализовано в приведенном ниже коде, но это очень легко сделать). Поскольку метод Guava ожидает поставщика, вы даже можете создать лямбду с этой логикой и передать ее непосредственно методу memoizeWithExpiration.

public MyResponse callUntilSuccess() {

    MyResponse response = myService.call();
    while (!response.isSuccessful()) {
        response = myService.call();
    }
    return response;
}   

Затем выполните памятку следующим образом:

private void createCache() {
    this.cache = Suppliers
         .memoizeWithExpiration(myService::callUntilSuccess, timeout,
                TimeUnit.MINUTES);
}   
...