What is a good way to implement Typesafe configuration reload

In a Scala application using Configes Config, I want to add the ability to reload Config at runtime. The Config instance is immutable. Here is what I still have:

package config trait Settings { private[config] var config: Config = ConfigFactory.empty() def engine: EngineSettings } trait EngineSettings { def weight: Int def offset: Int } class AppSettings { override def engine = new EngineSettings { override def weight = config.getInt("engine.weight") override def offset = config.getInt("engine.offset") } } object Settings { private val namedSettings = new TrieMap[String, AppSettings] def load(configName: String = "local"): Settings = { // load config // create or update AppSettings // add to map and return } } 

Initially, an instance of settings is created using the Settings.load parameter. This instance reference is passed to other classes. Then the second thread can reload the base Config by calling Settings.load again. Here's how you access it:

 class Engine(settings: Settings) { def calculate() = { val weight = settings.engine.weight // do some stuff val offset = settings.engine.offset } } 

There are two problems:

  • someone can reload the basic configuration while calculate () is in the line: // do some things (consistency)
  • I do not like to use var in setting

How can I improve this design :)

+7
java scala concurrentmodification typesafe-config
source share
1 answer

You can include config in a method that supports invalidation of the configuration cache (and with reasonable defaults) so that you can choose between dynamic (default in the following example) and performance.

In general, I suggest you use a good Scala typafe ConfigSafe Config package, such as Ficus (for example, Gradle - net.ceedubs:ficus_2.11:1.1.1 artifact dependency net.ceedubs:ficus_2.11:1.1.1 )

 package config import scala.collection.concurrent.TrieMap import com.typesafe.config.{Config, ConfigFactory} import net.ceedubs.ficus.Ficus._ trait Settings { protected[config] def config ( name: String = "local", invalidateCache: Boolean = false ): Config = { if (invalidateCache) { ConfigFactory invalidateCaches } ConfigFactory load name } def engine: EngineSettings } trait EngineSettings { def weight: Int def offset: Int } class AppSettings(val name: String = "local") extends Settings { val c = config() override def engine = new EngineSettings { override def weight = c.as[Int]("engine.weight") override def offset = c.as[Int]("engine.offset") } } object Settings { private val namedSettings = new TrieMap[String, AppSettings] def load(configName: String = "local"): Settings = { // eg val loadedUpToDate = new AppSettings namedSettings += ((configName + "." + System.currentTimeMillis, loadedUpToDate)) new Settings { override def engine = loadedUpToDate.engine } } } 

I think this solves your problems because:

  • Loading configuration dynamically by default with reboot
  • Using the method, you do not resort to mutable state
+1
source share

All Articles