[play-ws] Cache serving stale response instead of error

63 views
Skip to first unread message

Pablo Romanelli

unread,
Mar 6, 2018, 5:12:09 PM3/6/18
to Play Framework
Hi, I think I found a bug on play ws cache.

I'm requesting a resource with the following header:
  1. Accept-Ranges:
    bytes
  2. Cache-Control:
    max-age=20
  3. Connection:
    keep-alive
  4. Content-Length:
    271
  5. Content-Type:
    application/json
  6. Date:
    Tue, 06 Mar 2018 15:31:58 GMT
  7. ETag:
    "5a9ea88c-10f"
  8. Last-Modified:
    Tue, 06 Mar 2018 14:41:16 GMT
  9. Server:
    nginx/1.13.9
Play ws correctly makes request once every 20 seconds.
But if I shutdown the remote service, the ws client returns 200 OK responses instead of an error (that is what I'm expecting if the server is not available).
I even try with "max-age=20, stale-while-revalidate=30, stale-if-error=600" but after the "stale-if-error" time, the client continues to return 200 OK responses even if the HTTP service is offline.


I think this behaviour is due to the following code:

/**
* Calculates the time to live. Currently hardcoded to 24 hours.
*/
protected def calculateTimeToLive(request: Request, status: CacheableHttpResponseStatus, headers: CacheableHttpResponseHeaders): Option[DateTime] = {
Some(DateTime.now.plusHours(24))
}


I'm using play-ahc-ws-standalone 1.1.6 with Caffeine ("com.github.ben-manes.caffeine" % "caffeine" % "2.6.2") like this:

class CaffeineHttpCache @Inject()(config: Config)(implicit ec: ExecutionContext) extends Cache {
val underlying = Caffeine.newBuilder()
.build[EffectiveURIKey, ResponseEntry]()


override def remove(key: EffectiveURIKey) = Future(underlying.invalidate(key))

override def put(key: EffectiveURIKey, entry: ResponseEntry) = Future(underlying.put(key, entry))

override def get(key: EffectiveURIKey) = Future(Option(underlying.getIfPresent(key)))

override def close(): Unit = underlying.cleanUp()
}

object WsModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[ActorSystem]).toInstance(ActorSystem())
}

@Provides
@Singleton
def clientProvider(cache: CaffeineHttpCache)
(implicit actorSystem: ActorSystem, ec: ExecutionContext): StandaloneAhcWSClient = {
implicit val materializer = ActorMaterializer()
StandaloneAhcWSClient(httpCache = Some(new AhcHttpCache(cache)))
}
}


Thank you!

Will Sargent

unread,
Mar 6, 2018, 11:09:18 PM3/6/18
to play-fr...@googlegroups.com
Okay, I will look at this.

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/915ade12-212b-4b64-95a8-b722624cff95%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Will Sargent

unread,
Mar 6, 2018, 11:33:40 PM3/6/18
to play-fr...@googlegroups.com
What happens when you turn on logging?  The cache is deliberately chatty at TRACE level.
Reply all
Reply to author
Forward
0 new messages