Hi,
I try to implement a custom Cache class using Redis rather than EH Cache (cause application will be put on multiple app servers with load balancing).
Is plan in the release 2.5 to have a better cache implementation ? or with ability to use it on real production env (multiple app servers) ?
Java implementation of Play Cache seem not working. I got the following error :
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for play.cache.CacheApi was bound.
while locating play.cache.CacheApi
1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1042) ~[guice.jar:na]
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1001) ~[guice.jar:na]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051) ~[guice.jar:na]
at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:321) ~[play_2.11-2.4.6.jar:2.4.6]
at play.inject.DelegateInjector.instanceOf(DelegateInjector.java:22) ~[play_2.11-2.4.6.jar:2.4.6]
at play.cache.Cache.cacheApi(Cache.java:14) ~[play-cache_2.11-2.4.6.jar:2.4.6]
at play.cache.Cache.getOrElse(Cache.java:36) ~[play-cache_2.11-2.4.6.jar:2.4.6]
at models.AccountModel.getWalletBalanceAsCents(AccountModel.java:968) ~[classes/:2.4.6]
at models.AccountModel.getWalletBalance(AccountModel.java:1000) ~[classes/:2.4.6]
at views.html.clientview.SideBarClientView_Scope0$SideBarClientView.balance$1(SideBarClientView.template.scala:32) ~[classes/:na]
at views.html.clientview.SideBarClientView_Scope0$SideBarClientView.apply(SideBarClientView.template.scala:43) ~[classes/:na]
at views.html.clientview.HomeClientView_Scope0$HomeClientView.apply(HomeClientView.template.scala:41) ~[classes/:na]
at views.html.clientview.HomeClientView_Scope0$HomeClientView.render(HomeClientView.template.scala:80) ~[classes/:na]
at views.html.clientview.HomeClientView.render(HomeClientView.template.scala) ~[classes/:na]
at controllers.client.HomeClientController.GET_Home(HomeClientController.java:35) ~[classes/:na]
at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$31$$anonfun$apply$31.apply(Routes.scala:1781) ~[classes/:na]
at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$31$$anonfun$apply$31.apply(Routes.scala:1781) ~[classes/:na]
at play.core.routing.HandlerInvokerFactory$$anon$4.resultCall(HandlerInvoker.scala:136) ~[play_2.11-2.4.6.jar:2.4.6]
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$14$$anon$3$$anon$1.invocation(HandlerInvoker.scala:127) ~[play_2.11-2.4.6.jar:2.4.6]
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:70) ~[play_2.11-2.4.6.jar:2.4.6]
at Global$2.call(Global.java:84) ~[classes/:na]
at play.mvc.Security$AuthenticatedAction.call(Security.java:56) ~[play_2.11-2.4.6.jar:2.4.6]
at play.core.j.JavaAction$$anonfun$7.apply(JavaAction.scala:94) ~[play_2.11-2.4.6.jar:2.4.6]
at play.core.j.JavaAction$$anonfun$7.apply(JavaAction.scala:94) ~[play_2.11-2.4.6.jar:2.4.6]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:40) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:70) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:32) ~[play_2.11-2.4.6.jar:2.4.6]
at scala.concurrent.impl.Future$.apply(Future.scala:31) ~[scala-library-2.11.7.jar:na]
at scala.concurrent.Future$.apply(Future.scala:492) ~[scala-library-2.11.7.jar:na]
at play.core.j.JavaAction.apply(JavaAction.scala:94) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:105) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:105) ~[play_2.11-2.4.6.jar:2.4.6]
at play.utils.Threads$.withContextClassLoader(Threads.scala:21) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:104) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:103) ~[play_2.11-2.4.6.jar:2.4.6]
at scala.Option.map(Option.scala:146) ~[scala-library-2.11.7.jar:na]
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:103) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:96) ~[play_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:524) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:524) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:560) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:560) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$13.apply(Iteratee.scala:536) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$13.apply(Iteratee.scala:536) ~[play-iteratees_2.11-2.4.6.jar:2.4.6]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.7.jar:na]
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40) [akka-actor_2.11.jar:na]
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397) [akka-actor_2.11.jar:na]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) [scala-library-2.11.7.jar:na]
application.conf
play.modules.disabled += "play.api.cache.EhCacheModule"
play.modules.enabled += "modules.RedisCacheModule"
RedisCacheModule.java
package modules;
import play.Logger;
import play.api.Configuration;
import play.api.Environment;
import play.api.inject.Binding;
import play.api.inject.Module;
import play.cache.CacheApi;
import play.cache.NamedCacheImpl;
import scala.collection.Seq;
import javax.inject.Singleton;
public class RedisCacheModule extends Module {
@Override
public Seq<Binding<?>> bindings(final Environment environment, final Configuration configuration) {
final String defaultCacheName = configuration.underlying().getString("play.cache.defaultCache");
Logger.info("defaultCache: {}", defaultCacheName);
return seq(
bind(CacheApi.class).qualifiedWith(new NamedCacheImpl(defaultCacheName)).to(RedisCacheApi.class).in(Singleton.class)
);
}
}
RedisCacheApi.java
package modules;
import com.google.inject.Singleton;
import play.Logger;
import play.cache.CacheApi;
import java.util.concurrent.Callable;
@Singleton
public class RedisCacheApi implements CacheApi {
public RedisCacheApi() {
Logger.info("RedisCacheApi::constructor");
}
@Override
public <T> T get(String key) {
Logger.info("RedisCacheApi::get");
return null;
}
@Override
public <T> T getOrElse(String key, Callable<T> block, int expiration) {
Logger.info("RedisCacheApi::getOrElse");
return null;
}
@Override
public <T> T getOrElse(String key, Callable<T> block) {
Logger.info("RedisCacheApi::getOrElse");
return null;
}
@Override
public void set(String key, Object value, int expiration) {
Logger.info("RedisCacheApi::set");
}
@Override
public void set(String key, Object value) {
Logger.info("RedisCacheApi::set");
}
@Override
public void remove(String key) {
Logger.info("RedisCacheApi::remove");
}
}
Do you have any idea why it's not working ? In the worst case, i have to obtain a NullPointerException because all overrided methods return null. but here, the class RedisCacheApi is never used.