Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

specific config by environment in Scala

What is a good way to set up a project in Scala which uses different configuration depending on environments.

I need to specifically have different databases for development, test and production environment (similar to what is done in Rails)

like image 870
Daniel Cukier Avatar asked Feb 06 '14 15:02

Daniel Cukier


People also ask

What is ConfigFactory in Scala?

Configurations from a file By default, the ConfigFactory looks for a configuration file called application. conf. If willing to use a different configuration file (e.g.: another. conf), we just need to indicate a different file name and path to load (e.g.: ConfigFactory.

What is Typesafe config?

Typesafe Config allows you to store configuration into separated files and use include keyword to include configuration of those files.

What is application conf file?

An application configuration file is an XML file used to control assembly binding. It can redirect an application from using one version of a side-by-side assembly to another version of the same assembly. This is called per-application configuration.


3 Answers

Another strategy I'm using consists of using includes. I usually store my DEV settings in the default application.conf file then I create a new conf file for other environments and include the default one.

Let's say my DEV conf application.conf looks like this:

myapp {
    server-address = "localhost"
    server-port = 9000

    some-other-setting = "cool !"
}

Then for the PROD, I could have another file called prod.conf:

include "application"

# override default (DEV) settings
myapp {
    server-address = ${PROD_SERVER_HOSTNAME}
    server-port = ${PROD_SERVER_PORT}
}

Note that I override only the settings that change in the PROD environment (some-other-setting is thus the same as in DEV).

The config bootstrap code doesn't test anything

...
val conf = ConfigFactory.load()
...

To switch from the DEV to the PROD conf, simply pass a system property with the name of the config file to load:

java -Dconfig.resource=prod.conf ...

In DEV, no need to pass it since application.conf will be loaded by default.

So here we're using Typesafe Config's default loading mechanism to achieve this.

I've created a simple project to demonstrate this technique. Feel free to clone and experiment.

like image 87
ozeebee Avatar answered Oct 07 '22 18:10

ozeebee


Use typesafe Config. Create a Config object like this:

import com.typesafe.config._

object Config {
  val env = if (System.getenv("SCALA_ENV") == null) "development" else System.getenv("SCALA_ENV")

  val conf = ConfigFactory.load()
  def apply() = conf.getConfig(env)
}

Then create the application.conf file in src/main/resources folder:

development {
  your_app {
    databaseUrl = "jdbc:mysql://localhost:3306/dev_db"
    databaseUser = "xxxx"
    databasePassword = "xxxx"
  }
}
test {
  your_app {
    databaseUrl = "jdbc:mysql://localhost:3306/test_db"
    databaseUser = "xxxxx"
    databasePassword = "xxxx"
  }
}

Now from anywhere in your application, you can access configuration:

Config().getString("your_app.databaseUrl")

If you have your environment set up (e.g. export SCALA_ENV=test) when you run your application, it will consider the right configuration section. The default is development

like image 27
Daniel Cukier Avatar answered Oct 07 '22 16:10

Daniel Cukier


I wasn't happy with how Daniel Cukiers solution did not allow defaults and overrides, so I changed it around to make full use of those.

The only configuration you have to do is set a ENVIRONMENT variable on the system (defaults to 'dev' if none is set)

(Java solution, compatible with Scala):

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

public class MyCompanyConfig {
    public final static Config base = ConfigFactory.load().getConfig("mycompany");
    public final static String environment = System.getenv("ENVIRONMENT") == null ? "dev" : System.getenv("ENVIRONMENT");

    /**
     * Returns a subtree of the base configuration with environment settings applied.
     *
     * @param setting The subtree to return config for.
     * @return A config with base in given setting, with environment modifications applied.
     */
    public static Config load(String setting) {

        Config config = base.getConfig(setting);

        if (config.hasPath(environment)) {
            return config.getConfig(environment).withFallback(config);
        }

        return config;
    }
}

This allows a single reference.conf in a library looking like this:

mycompany.module1 {
    setting1 : "adefaultvalue"
    url : "localhost"

    test {
        // will be used where ENVIRONMENT="test"
        url : "test.mycompany.com"
    }

    prod {
        // will be used where ENVIRONMENT="prod"
        setting1 : "changethedefault"
        url : "www.mycompany.com"
    }
}

Usage:

Config conf = MyCompanyConfig.load("module1")
like image 2
DHa Avatar answered Oct 07 '22 16:10

DHa