Provisions

A Provision is a wrapper of a singleton object that can be constructed by using a java.util.Properties instance.

Provisions solve several problems that arise in configuration-oriented Nstream codebases, including:

Overview

Upon initial startup (via nstream.adapter.runtime.AppPlane#main) an Nstream server loads all declared Provisions under the top-level provisions block in server.recon.

If you wish to use a custom main method but still keep this behavior, just invoke the following logic

import nstream.adapter.runtime.ToolkitLoader;
// ...

// Load provisions and return a handle to server config structure
final Value serverStructure = ToolkitLoader.loadConfig();
// Run server
ToolkitLoader.runKernel();

Once a Provision<T> is successfully declared under name, then its value can be read at any time via ProvisionLoader<T>.get(name).value().

Avoid namespace collisions

Loading multiple provisions with the same name will result in undefined behavior, and not necessarily throw a reliable exception.

Note: the IngressSettings and EgressSettings definitions from some adapter libraries contain fields that refer to provision names. The corresponding patch implementations read these fields and invoke the aformentioned get() method. This is how Nstream provides config-only pathways for common-case situations even when independently-loaded singletons are required.

Declaration Styles

Inline

The following server.recon snippet declares a ConnectionPoolProvision under the name hikari, and a separate PropertiesProvision under the name consumer-props.

provisions: {
  @provision("hikari") {
    # class must extend
    #  nstream.adapter.common.provision.AbstractProvision
    class: "nstream.adapter.jdbc.ConnectionPoolProvision"
    def: {
      "dataSource.driver": "oracle.jdbc.OracleDriver"
    }
  },
  @provision("consumer-props") {
    class: "nstream.adapter.common.provision.PropertiesProvision",
    def: {
      "bootstrap.servers": "broker:9092",
      "group.id": "fooGroup",
      "auto.offset.reset": "latest"
    }
  }
}

External Config File

Use use in place of def to load from a configuration file (falling back to a Java resource).

# /path/to/consumer.properties
bootstrap.servers=broker:9092
group.id=fooGroup
auto.offset.reset=latest
# server.recon
provisions: {
  @provision("consumer-props") {
    class: "nstream.adapter.common.provision.PropertiesProvision",
    use: "/path/to/consumer.properties"
  }
}

Environment-Sensitive Inline

The syntax @config { env: ..., prop: ..., def: ...} can replace any inline property. This indicates to evaluate a specified environment variable, or fall back to a specied system property, or fall back to a specified default definition. The env/prop/def priority order is enforced regardless of the order of declaration.

provisions: {
  @provision("consumer-props") {
    class: "nstream.adapter.common.provision.PropertiesProvision",
    def: {
      "bootstrap.servers": @config {
        env: "BOOTSTRAP_SERVERS"
        prop: "bootstrap.servers"
        def: "bootstrap-server:9092"
      },
      "group.id": "fooGroup"
    }
  }
}

Note: all three of env/prop/def are technically optional, though a RuntimeException will occur if evaluating the expression results in no defined value.

Environment-Sensitive External Config File

The syntaxes discussed in the previous two sections can be combined.

provisions: {
  @provision(complex) {
    class: "nstream.adapter.common.provision.PropertiesProvision"
    use: {
      "loadconf/base.properties",
      @config {
        env: "SECRET_PROPERTIES_FILE"
        prop: "secret.properties.file"
        def: "loadconf/unused.properties"
      }
    }
    def: {
      "value.deserializer": "org.apache.kafka.common.serialization.IntegerDeserializer"
      # This is ignored if loadconf/base.properties OR the @config evaluation result is
      #  a file that includes a bootstrap.servers property; otherwise, it is evaluated
      #  normally and appended to the definition.
      "bootstrap.servers": @config {
        env: "BOOTSTRAP_SERVERS"
        prop: "bootstrap.servers"
        def: "bootstrap-server:9092"
      }
    }
  }
}

Usage Tips


Nstream is licensed under the Redis Source Available License 2.0 (RSALv2).