The most delightful and handy Node.js client for Ctrip's apollo configuration service, which
ctrip-apollo
ctrip-apollo
directly uses async/await
and requires node >= 7.10.1
apollo-declare
For some scenarios, we want to:
Then you can try apollo-declare
$ npm i ctrip-apollo
const apollo = require('ctrip-apollo')
const app = apollo({
host: 'http://localhost:8070',
appId: '100004458'
})
// Get the default namespace
const namespace = app.namespace()
// Namespace is an EventEmitter of nodejs
.on('change', ({
key,
oldValue,
newValue
}) => {
// Updates new values to `process.env`
process.env[key] = newValue
})
// - Fetch configurations for the first time
// - start update notification polling (by default)
namespace.ready()
.then(() => {
console.log(namespace.get('portal.elastic.cluster.name'))
// 'hermes-es-jp'
// THen, go and change/publish configurations in apollo admin
console.log(namespace.get('portal.elastic.cluster.name'))
// 'hermes-es-us'
// <----
// ctrip-apollo handles update notifications in the background
console.log(process.env['portal.elastic.cluster.name'])
// 'hermes-es-us'
})
const ns = apollo({
host,
appId,
// Save local cache to the current directory
cachePath: __dirname
})
.cluster('my-cluster')
.namespace('my-namespace')
const start = async () => {
// We can also use async/await
await ns.ready()
console.log(ns.config())
// {
// 'portal.elastic.document.type': 'biz',
// 'portal.elastic.cluster.name': 'hermes-es-fws'
// }
}
start()
and enable fetching on every 3 minutes
const app = apollo({
host,
appId,
enableUpdateNotification: false,
enableFetch: true,
fetchInterval: 3 * 60 * 1000
})
client.ready()
.then(() => {
console.log(client.get('portal.elastic.cluster.name'))
// might be:
// 'hermes-es-us'
})
const ns = await
apollo({host, appId}) // <-- app
.cluster('ap-northeast-1') // <-- cluster
.enableUpdateNotification(true) // <-- cluster
.namespace('account-service') // <-- namespace
.enableFetch(false) // <-- namespace
.ready() // <-- Promise {namespace}
console.log(ns.get('account.graphql.cluster.name'))
// might be:
// graph-us-3
By default, ctrip-apollo
and apollo admin service store configurations in java.util.Properties
format.
If we have two namespaces.
The one is account-service
which stores configurations in JSON,
{
"redis.sentinel.port": 6379
}
while the other one asset-service
in properties
redis.sentinel.port=6379
const cluster = apollo({host, appId}).cluster('ap-northeast-1')
// in JSON format
cluster.namespace('account-service', 'JSON') // <=====
.ready()
// .ready() resolves the namespace instance
.then(account => {
console.log(account.get('redis.sentinel.port')) // 6379
})
cluster.namespace('asset-service')
.ready()
.then(asset => {
console.log(asset.get('redis.sentinel.port')) // '6379'
})
app (client) config service
| | | |
|-- cluster <----- long polling --------| | |
| | | |
| |-- namespace <------- fetch ---------| |
| |
|-- cluster <-------- long polling ---------|
ApolloApplication
An application can have one or more clusters
Object
Essential options:
URL::host
the host (including protocol, hostname and port) of the apollo config servicestring
apollo application idOptional options:
boolean=true
set to false
to disable update notification.PollingRetryPolicy=apollo.DEFAULT_POLLING_RETRY_POLICY
boolean=false
set to true
to enable the featurenumber=0
timeout in milliseconds before the initial fetch or interval fetch result in an FETCH_TIMEOUT
error.number=5 * 60 * 1000
interval in milliseconds to pull the new configurations. Defaults to 5
minutes. Setting this option to 0
will disable the feature.boolean=true
whether refresh configurations by fetching the restful API with caches. Defaults to true
. If you want to always fetch the latest configurations (not recommend), set the option to false
path
specify this option to enable the feature to save configurations to the diskboolean=false
whether a namespace should skip the initial fetching if the corresponding cache is found on disk.Returns ApolloApplication
If options.enableUpdateNotification
is set to true
(the default value), all clusters will start to receive update notification automatically.
Make sure the timeout of your gateway is configured more than 60 seconds, via
If options.enableFetch
is set to true
(default value is false
), all namespaces will fetch new configurations on every time period of options.fetchInterval
true
the client tries to read local cache first, if the cache is found, then it will skip the initial fetching.false
the client tries to fetch configuration from config service first, if it fails, it will try to read the local cacheIf neither reading local cache nor fetching from remote comes successful, await namespace.ready()
will fail.
string='default'
the cluster name. The cluster name defaults to 'default'
Creates a new cluster under the current application.
Returns ApolloCluster
string='application'
the optional namespace name which defaults to 'application'
which is the default namespace name of Ctrip's Apollo config service.enum<PROPERTIES|JSON>=PROPERTIES
the type of the configuration format syntax. Defaults to 'PROPERTIES'
Create a new namespace under the default cluster of the current application
Returns ApolloNamespace
.
ApolloCluster
A cluster can have one or more namespaces. And all namespaces of the same cluster use a single polling manager to receive update notifications.
string='application'
Creates a new namespace of the current cluster.
Returns ApolloNamespace
boolean
Enable or disable the updateNotification. Returns this
// Get the default cluster, which is equivalent to
// app.cluster('default')
const cluster = app.cluster()
// Disable update notification
cluster.enableUpdateNotification(false)
ApolloNamespace
A namespace is what a configuration key belongs to.
Fetch the configuration from config service for the first time, or fallback to reading the local cache file, and if options.skipInitFetchIfCacheFound
is set to false
(the default value).
If it fails to fetch configurations and read local cache, this method will reject.
MAKE SURE we await namespace.ready()
before any namespace.config()
or namespace.get()
methods are invoked.
Returns Object
the shallow copy of all configurations for the current namespace / application.
Notice that, all configuration getters of a namespace are synchronous methods
console.log('application config', namespace.config())
string
config key nameReturns the config value of the corresponding key key
console.log('config for host', namespace.get('host'))
new in 4.4.0
Check if a key is in the config.
boolean
Enable or disable fetching in every options.fetchInterval
Returns string
the namespace name
Returns string
name of the cluster which the current namespace belongs to
Returns string
the cluster name
'change'
string
key of the configuration that has been changedany
the old value of the configurationany
the new value of the configuration that has been set.Emits if the any configuration changes.
By default, ctrip-apollo
uses HTTP long polling to listen the changes of the configurations.
namespace.on('change', e => {
console.log('key', e.key)
console.log('oldValue', e.oldValue)
console.log('newValue', e.newValue)
})
'add'
string
any
the value of the newly added configurationEmits if a new configuration key has been added
'delete'
string
any
the value of the configuration that has been deleted.Emits if a configuration key has been deleted
If options.fetchInterval
is set to 0
and options.updateNotification
is set to false
, then the event will never emit.
'updated'
Added in 4.2.0, event data added in 4.5.0
object
the old configobject
the new config after updatedEmits after all changes, adding and deletion of the current updation have been processed.
'fetch-error'
Emits if it fails to fetch configurations
'save-error'
Emits if it fails to save configurations to local cache file
PollingRetryPolicy
is to tell the system what to do next if an error occured when receiving update notifications.
type PollingRetryPolicy = Function(retries): PollingRetryDirective
number
how many times has retried till the last error.interface PollingRetryDirective {
// `abandon: true` ignores all properties below
// and stops update notification polling which is a dangerous directive.
abandon?: boolean
// After `delay` milliseconds,
// it will try to poll the update notification again
delay?: number
// Tells the system to reset the `retries` counter.
// And the `retries` counter always reset to zero if it receives a sucessful notification
reset?: boolean
}
// If there is no properties set, it will retry immediately.
The default pollingRetryPolicy
is equivalent to:
// It schedule the first retry in 10 seconds, and adds extra 10s delay everytime.
// It will reset the `retries` counter after the 6th retry.
const {DEFAULT_POLLING_RETRY_POLICY} = require('ctrip-apollo')
And we can define our own policy
const pollingRetryPolicy = retries => ({
// Stop polling after 11(the first and the latter 10 retries) errors
abandon: retries >= 10,
// Longer and longer delays
delay: retries * 10 * 1000
// And no reset
})
const app = apollo({
...,
pollingRetryPolicy
})
Array
List of available option keys.
See error.js for details