tox1cozZ
aka Agravaine
- 8,456
- 598
- 2,893
Есть задача реализовать простые муты игроков в чате. Данные о мутах хранятся в БД. Соответственно, при отправке сообщения игроков нужно делать запрос в БД и смотреть, может ли он писать в чат.
Запрос в бд - дело не быстрое, к тому же это нужно делать очень часто, ибо чат может быть довольно активным.
В Guava есть такая штука прикольная, Suppliers.memoizeWithExpiration - своеобразный кэш для одного элемента:
Мы вызываем get(), идет подгрузка данных и кешируется. 60 секунд мы сможет дергать get() и у нас будет сразу возвращаться значение из кеша. И только через 60 секунд снова перезагрузятся данные.
Удобно, красиво, отлично подходит чтобы постоянно не лазить в базу.
Но это все происходит в том же потоке, что все равно может повесить сервер.
Пытался реализовать это дело асинхронно - вот что вышло:
Вроде всё работает как надо. Но сомневаюсь, что правильная реализация, может можно как-то сделать проще и красивее?
И да, prevValue запоминает текущее значение и передает его в getNow, чтобы пока подгружаются данные мы получали предыдущий результат, а не нулл(нулл - рабочее значение).
get() дергать у фьючи нельзя, ибо он блокирубщий(кэп).
Запрос в бд - дело не быстрое, к тому же это нужно делать очень часто, ибо чат может быть довольно активным.
В Guava есть такая штука прикольная, Suppliers.memoizeWithExpiration - своеобразный кэш для одного элемента:
Java:
Supplier<String> task = Suppliers.memoizeWithExpiration(() -> {
try{
// Large task
Thread.sleep(1000L);
return RandomStringUtils.randomAlphanumeric(12);
}catch(Throwable e){
return "ERROR";
}
}, 60L, TimeUnit.SECONDS);
String value = task.get();
Удобно, красиво, отлично подходит чтобы постоянно не лазить в базу.
Но это все происходит в том же потоке, что все равно может повесить сервер.
Пытался реализовать это дело асинхронно - вот что вышло:
Java:
AtomicReference<String> prevValue = new AtomicReference<>();
Supplier<CompletableFuture<String>> calculated = Suppliers.memoizeWithExpiration(() -> CompletableFuture.supplyAsync(() -> {
try{
// Large task
Thread.sleep(1000L);
return RandomStringUtils.randomAlphanumeric(12);
}catch(Throwable e){
return "ERROR";
}
}).thenApply(res -> {
prevValue.set(res);
return res;
}), 60L, TimeUnit.SECONDS);
String result = calculated.get().getNow(prevValue.get());
И да, prevValue запоминает текущее значение и передает его в getNow, чтобы пока подгружаются данные мы получали предыдущий результат, а не нулл(нулл - рабочее значение).
get() дергать у фьючи нельзя, ибо он блокирубщий(кэп).