Play seems to initialize ebean prior to reading the configuration

Hi,

I am working with Play 2.6.23 and Ebean 11.15.12

sbt-play-ebean plugin: 4.1.3

We are experiencing this error when trying to create default EbeanServer.

It doesn’t happen all the time but usually the problem arises after we add a jar to the project

but it can happen also after some code changes

this is the exception:

[ERROR] [i.e.Ebean] [main] -Error trying to create the default EbeanServer
java.lang.RuntimeException: DataSource user is null?
at org.avaje.datasource.pool.ConnectionPool.(ConnectionPool.java:207)
at org.avaje.datasource.core.Factory.createPool(Factory.java:15)
at io.ebeaninternal.server.core.DefaultContainer.getDataSourceFromConfig(DefaultContainer.java:334)
at io.ebeaninternal.server.core.DefaultContainer.setDataSource(DefaultContainer.java:278)
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:117)
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:88)
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:45)
at io.ebean.EbeanServerFactory.create(EbeanServerFactory.java:58)
at io.ebean.Ebean$ServerManager.getWithCreate(Ebean.java:202)
at io.ebean.Ebean$ServerManager.(Ebean.java:160)
at io.ebean.Ebean$ServerManager.(Ebean.java:133)
at io.ebean.Ebean.(Ebean.java:127)
at com.firemon.cloudmon.infrastructure.InfrastructureModule.create(InfrastructureModule.java:30)
at com.firemon.cloudmon.infrastructure.InfrastructureModule$$FastClassByGuice$$14e5d7e8.invoke()
at com.google.inject.internal.ProviderMethod$FastClassProviderMethod.doProvision(ProviderMethod.java:264)
at com.google.inject.internal.ProviderMethod.doProvision(ProviderMethod.java:173)
at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(InternalProviderInstanceBinding Impl.java:185)
at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(InternalProviderInstanceBindingImpl.java:162)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:168)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:39)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:42)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:65)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:306)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:62)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:168)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:39)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:42)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:65)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:306)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:42)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:65)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:306)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:42)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:65)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:306)
at com.google.inject.internal.InjectorImpl$1.get(InjectorImpl.java:1050)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1086)
at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:442)
at play.api.inject.ContextClassLoaderInjector.$anonfun$instanceOf$3(Injector.scala:119)
at play.api.inject.ContextClassLoaderInjector.withContext(Injector.scala:127)
at play.api.inject.ContextClassLoaderInjector.instanceOf(Injector.scala:119)
at play.api.inject.RoutesProvider.$anonfun$get$2(BuiltinModule.scala:113)
at scala.Option.fold(Option.scala:158)
at play.api.inject.RoutesProvider.get$lzycompute(BuiltinModule.scala:113)
at play.api.inject.RoutesProvider.get(BuiltinModule.scala:108)
at play.api.inject.RoutesProvider.get(BuiltinModule.scala:102)
at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:85)
at com.google.inject.internal.BoundProviderFactory.provision(BoundProviderFactory.java:77)
at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:59)
at com.google.inject.internal.BoundProviderFactory.get(BoundProviderFactory.java:61)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:42)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:65)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:306)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:62)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:168)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:39)
at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:211)
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:182)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:109)
at com.google.inject.Guice.createInjector(Guice.java:87)
at com.google.inject.Guice.createInjector(Guice.java:78)
at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:200)
at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:154)
at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:25)
at play.core.server.ProdServerStart$.start(ProdServerStart.scala:53)
at play.core.server.ProdServerStart$.main(ProdServerStart.scala:27)
at play.core.server.ProdServerStart.main(ProdServerStart.scala)

The code for getting the EbeanServer resides within a Guice module

@Provides @Singleton EbeanServer create(EbeanConfig ebeanConfig) { String server = ebeanConfig.defaultServer(); log.info("Default server: " + server); return Ebean.getServer(server); }

the configuration is
default.driver=org.postgresql.Driver
default.url=“jdbc:postgresql://localhost/<DB_name>”
default.username=“username”
default.password=“password”

We have experienced it a few times and “fixed” it by making some changes to the config file

using the JVM -D option to declare variables instead of the config file… (this type of vudu)

these attempts work for a short while and then pop up again

After investigating this deeper I saw that there is a static instantiation of the ServerManager (within Ebean class)

The exception is thrown from this context and it depends on the state of the skip flag in PrimaryServer class

This is the constructor of the ServerManager
private ServerManager() {
try {
if (!PrimaryServer.isSkip()) {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug(“defaultName:{}”, defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
}
} catch (Throwable e) {
logger.error(“Error trying to create the default EbeanServer”, e);
throw new RuntimeException(e);
}
}

I saw that when the skip is false the exception is thrown, otherwise everything works

I can’t figure out why the skip state behaves differently

Only thing I could think of is that since this is static initialization then it depends on the order which the classes are loaded

did anyone encounter this?

Any known solution or workaround?

Thanks

Nir

Hi,

I experienced this earlier on, and in my case it was caused by some actors started by Akka Quartz Scheduler wanting to get access to the database before the database was initiated. It never happened in dev mode and happened maybe 5% of the times in prod mode, which made it really hard to troubleshoot.

Anyway, I added a 10 seconds delay before initiating the different schedules and the problem was gone.

Please also have a look at this: https://stackoverflow.com/questions/52180453/play-framework-2-6-x-ebean-datasource-is-null-in-production-only

Kind regards,
Eirik

Hi

Thanks for the answer
After reading this and the stackoverflow post I came to the conclusion that in my case the problem is ( or at least seems to be) that the DynamicEvolutions was not ready at the time I tried to create the EbeanServer
All I did was to inject DynamicEvolutions to my provider which forced guice to run it’s constructor.

The problem is gone
Hope it stays this way :slight_smile: