vulcain-corejs
Version:
Vulcain micro-service framework
167 lines (165 loc) • 6.26 kB
JavaScript
"use strict";
const system_1 = require("./../globals/system");
const configurationManager_1 = require("../configurationSources/configurationManager");
const propertiesFactory_1 = require("./propertiesFactory");
const configurationSourceBuilder_1 = require("../configurationSources/configurationSourceBuilder");
const rx = require("rx");
const conventions_1 = require("../../utils/conventions");
/**
*
* Provides dynamic properties updated when config change.
* Accessing a dynamic property is very fast. The last value is cached and updated on the fly
* from a <b>ConfigurationSource</b> at fixed interval.
* Updates are made using polling requests on a list of sources.
* <p>
* Dynamic properties are read only. You can set a value but it will be valid only as a default value.
* </p>
* <code>
* let i:number = DynamicProperties.instance.getProperty("prop1");
* let i2:number = DynamicProperties.instance.getOrDefaultProperty("prop1", 1);
* </code>
*/
class DynamicProperties {
/**
* Private constructor
* <param name="pollingIntervalInSeconds"></param>
* <param name="sourceTimeoutInMs"></param>
*/
constructor(pollingIntervalInSeconds, sourceTimeoutInMs) {
this._properties = new Map();
this._propertyChanged = new rx.Subject();
this._factory = new propertiesFactory_1.PropertiesFactory(this);
this.reset(pollingIntervalInSeconds, sourceTimeoutInMs);
}
/// <summary>
/// Raises when a property has changed
/// </summary>
get propertyChanged() {
return this._propertyChanged;
}
/**
* for test only
*/
// static __forcePollingAsync() {
// return DynamicProperties.instance._configurationManager.startAsync();
// }
/// <summary>
/// Get the dynamic properties factory
/// </summary>
static get factory() {
return DynamicProperties.instance._factory;
}
/// <summary>
/// Get a singleton instance
/// </summary>
static get instance() {
if (!DynamicProperties._instance) {
DynamicProperties.init();
}
return DynamicProperties._instance;
}
/// <summary>
/// Initialise dynamic properties configuration. Can be call only once and before any call to DynamicProperties.instance.
/// </summary>
/// <param name="pollingIntervalInSeconds">Polling interval in seconds (default 60)</param>
/// <param name="sourceTimeoutInMs">Max time allowed to a source to retrieve new values (Cancel the request but doesn't raise an error)</param>
/// <returns>ConfigurationSourceBuilder</returns>
static init(pollingIntervalInSeconds, sourceTimeoutInMs) {
if (DynamicProperties._instance)
DynamicProperties._instance.reset();
DynamicProperties._instance = new DynamicProperties(pollingIntervalInSeconds || 60, sourceTimeoutInMs || 1000);
return new configurationSourceBuilder_1.ConfigurationSourceBuilder(DynamicProperties._instance._configurationManager);
}
addProperty(name, prop) {
this._properties.set(name, prop);
}
static registerPropertyAsDependency(name, defaultValue) {
let p = system_1.System.manifest.configurations[name];
if (p && p !== "any")
return;
let schema = "any";
if (typeof defaultValue === "number" || defaultValue) {
schema = typeof defaultValue;
}
system_1.System.manifest.configurations[name] = schema;
}
/**
/// Reset configuration and properties.
/// All current properties will be invalid and all current sources will be lost.
/// </summary>
/// <param name="pollingIntervalInSeconds"></param>
/// <param name="sourceTimeoutInMs"></param>
*/
reset(pollingIntervalInSeconds, sourceTimeoutInMs) {
this._propertyChanged.dispose();
this._propertyChanged = new rx.Subject();
let tmp = this._properties;
let tmp2 = this._configurationManager;
this._properties = new Map();
this._configurationManager = new configurationManager_1.ConfigurationManager(this, pollingIntervalInSeconds || 60, sourceTimeoutInMs || 2000);
if (tmp) {
for (let prop of tmp.values()) {
if (prop.dispose)
prop.dispose();
}
tmp.clear();
}
if (tmp2)
tmp2.dispose();
}
get pollingIntervalInSeconds() {
return this._configurationManager ? this._configurationManager.pollingIntervalInSeconds : 0;
}
onPropertyChanged(property, action) {
system_1.System.log.info(null, "CONFIG: Property changed " + property.name);
this._propertyChanged.onNext(property);
}
// for tests only
startPollingAsync(source) {
return this._configurationManager.startAsync(source && [source], false);
}
/// <summary>
/// Get a property or null if not exists
/// </summary>
/// <param name="name">Property name</param>
/// <returns>A dynamic property instance or null if not exists.</returns>
getProperty(name) {
let prop = this._properties.get(name);
if (!prop) {
if (!prop) {
let env = process.env[conventions_1.Conventions.toEnvironmentVariableName(name)];
if (env !== undefined) {
prop = this._factory.asProperty(env, name, true);
}
}
}
return prop;
}
clear() {
this._properties.clear();
}
Updater_getOrCreate(name, factory) {
let prop = this._properties.get(name);
if (!prop) {
prop = factory();
this._properties.set(name, prop);
}
return prop;
}
Updater_removeProperty(name) {
let p = this._properties.get(name);
p && p.reset();
}
dispose() {
for (let prop of this._properties.values()) {
if (prop.dispose)
prop.dispose();
}
this._configurationManager.dispose();
this._properties.clear();
this._factory = null;
this._propertyChanged.dispose();
}
}
exports.DynamicProperties = DynamicProperties;
//# sourceMappingURL=dynamicProperties.js.map