Caching an action in a multi-language website using Play Framework's Cached API
Asked Answered
C

2

20

In order to cache actions per label and language for a given number of seconds, I wrote the following helper method (where label, is the name I give to my action):

def cacheResponseFor(label: String, duration: Int)(action: EssentialAction) = { 
   Cached({r: RequestHeader => (label + getLanguage(r))}, duration){ action }
}

def getLanguage(request: RequestHeader): String = {
   request.cookies
     .get(helpers.SessionHelpers.LANGUAGE_SESSION)
        .map(_.value)
          .getOrElse(helpers.LanguageHelpers.FRENCH)
}

But I'm experiencing something weird, when I try to cache an Action for 60s and switch languages in the meantime to English from French for example, I keep getting the French version for 60s then it switches to english.

After investigating, I found that method getLanguage is not called at each call to that action as if the Key gets evaluated only after the caching period ends.

This is not right, I would want this cacheResponseFor to be called everytime I request my page, the language gets evaluated using getLanguage and I get the right cached version, i.e. I should end up with 2 cached actions (one per language).

Am I missing something?

Colloquium answered 24/10, 2015 at 15:9 Comment(3)
looks really weird it may even be a play bug, did you check where the cached version comes from? Is it cached at client(server will return NotModified) or cached in server side?Killie
It is supposed to be cached on server side, server returns 200 OkColloquium
Could it be that your LANGUAGE_SESSION is not yet changed for the new request, thus hitting the cache with the previous one set? the getOrElse will not be triggered if you have LANGUAGE_SESSION already set.Christeenchristel
E
1

Maybe the problem is in the getLanguage method. Try this, as recommended by the docs:

def getLanguage(request: RequestHeader): String = {
    request.acceptLanguages
           .map(_.code)
           .headOption
           .getOrElse(helpers.LanguageHelpers.FRENCH)
}

Also, take a look at Controller.request2lang() method and see if it could be helpful to you.

Ecphonesis answered 6/1, 2016 at 4:13 Comment(0)
R
1

I do not know what is the issue you are facing but I did a small proof of concept and there is no issue at all.

package controllers

import play.api.cache.Cached
import play.api.mvc.{Action, Controller, EssentialAction, RequestHeader}

object Caches {
  import play.api.Play.current

  def cacheResponseFor(label: String, duration: Int)(action: EssentialAction) = {
    Cached({r: RequestHeader => label + getLanguage(r)}, duration){ action }
  }

  def getLanguage(request: RequestHeader): String = {
    request.cookies
      .get("language")
      .map(_.value)
      .getOrElse("fr")
  }
}

class CachedApplication () extends Controller {

  import Caches._

  def index = cacheResponseFor("homePage", 60) {
    Action { implicit req =>
      getLanguage(req) match {
        case "fr" =>
          Ok("Bonjour le monde")
        case _ =>
          Ok("Hello world")
      }
    }
  }
}
Regeneration answered 17/2, 2016 at 11:37 Comment(4)
Did you switch languages during the 60 seconds period?Colloquium
Yes, changing the cookie and reloading the pageRegeneration
I even debugged it and saw getLanguage being called two times for a non cached request and one for a cached request.Regeneration
Weird, will try to check this out on the weekend, will let you know.Colloquium

© 2022 - 2024 — McMap. All rights reserved.