New Feature: dynamic_config
The ApplicationModuleMetadata
interface has been updated with a new configuration parameter: dynamic_config
.
This parameter takes the format of a ValueProvider
| FactoryProvider
, which can pull in other providers in order to generate configuration data.
The value merge priorities have been updated to the following:
- values provided via module definitions
- values provided via bootstrap
- values loaded via dynamic config
- values loaded from configuration files
- values loaded from environment variables
- values loaded from command line switches
Use Case: Centralized configuration provider
At the beginning of the bootstrapping sequence, the application perform a http request to a central configuration provider in order to retrieve additional auth keys. These keys could then be injected / refined via the normal @InjectConfig
mechanisms
Gotchas
This value is resolved at the extreme start of bootstrapping. Care needs to be taken to not create chicken-and-egg situations. It is best for loaders to be extremely lean in their dependences
Example
loader.ts
import { AbstractConfig, AutoLogService, FetchService } from "@digital-alchemy/boilerplate";
import { is, SECOND, sleep, START } from "@digital-alchemy/utilities";
import { hostname, userInfo } from "os";
import { exit } from "process";
type SystemInitResponse = { config: AbstractConfig };
const { username } = userInfo();
const name = hostname();
const ATTEMPTS = 10;
export const CONFIG_LOADER = (app: string) => ({
inject: [FetchService, AutoLogService],
async useFactory(fetch: FetchService, logger: AutoLogService) {
for (let i = START; i <= ATTEMPTS; i++) {
const configuration = await fetch.fetch<SystemInitResponse>({
rawUrl: true,
url: `http://central.control/init/identify/${username}/${name}/${app}`,
});
if (is.object(configuration)) {
return configuration.config;
}
logger.warn(`Failed to load configuration. Attempt [%s]/[%s]`, i, ATTEMPTS);
await sleep(SECOND);
}
logger.fatal(`FAILED TO LOAD CONFIGURATION`);
exit();
},
});
app.ts
import { ApplicationModule } from "@digital-alchemy/boilerplate";
import { CONFIG_LOADER } from "./loader"
@ApplicationModule({
dynamic_config: CONFIG_LOADER("special-app"),
})
export class MyApplication {}