What is the correct way to cache the result of future in playframework. E.g.:
val userGravatar: Future[JsValue] = RemoteGravatarService.get(user.id, user.email)
object RemoveGravatarService {
def get(userId: String, email: String): Future[JsValue] = {
Cache.getOrElse("gravatar-for-$userId", 1.hour) {
WS.url("gravatar.com/email=$email").get().asJson
}
}
}
We don't want to ask (this fictional) "Gravatar" every time, because it doesn't change that often. But we need som userGravatar info quite often locally.
Here we cache the future itself, but actually we only want to cache the result of the future. Is there a convenient/correct way to do this in play?
There isn't a method in Play's API that will handle Future
s. You can wrap Play's cache API to handle the orElse
case where it returns a Future
. Generically:
object FutureCache {
def getOrElse[A](key: String, expiration: Int)(orElse: => Future[A])
(implicit app: Application, ct: ClassTag[A], ec: ExecutionContext): Future[A] = {
Cache.getAs[A](key).map(Future.successful).getOrElse {
val value = orElse
value onSuccess { case result => Cache.set(key, result, expiration) }
value
}
}
}
Usage:
FutureCache.getOrElse[JsValue]("gravatar-for-$userId", 3600) {
WS.url("gravatar.com/email=$email").get().map(_.json)
}
You could also create an overload for getOrElse
that uses Duration
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With