Microbe is an abstraction for the repetitive task of setting basic express infrastructure each time we bring up another μService.
new Microbe([root = process.cwd()])
- create an instance of a service passing it's name (used for loggers etc.) and root directory (for operational endpoitns etc.)Microbe.build()
- builds the system, needs to be called before startingMicrobe.start(port)
- starts the server on given portMicrobe.container
- returns instance of DI containerMicrobe.configure(configPath)
- loads yml file into canister.js configurationMicrobe.before(middleware)
- attaches middleware to run before any routes are evaluatedMicrobe.after(middleware)
- attaches middleware to run after routes are evaluatedMicrobe.route() : express.Router
- returns an instance of Router, attach your handlers hereMicrobe.health(callback)
- adds a health checker per uw-lib-operational.jsMicrobe.ready(callback)
- sets a ready checker per uw-lib-operational.jsMicrobe.bootstrap() : Promise
- runs bootstrap methods (if any) in order and returns PromiseMicrobe.teardown() : Promise
- runs teardown methods (if any) in reverse order and returns Promise
There's both request and error logging via bunyan available out of the box.
A request scope logger, with request-id
and x-request-id
is available on req.logger
property.
Available in the container via get('instrumentation')
. Default heap and request durations are preconfigured as well as /__/metrics
for reporter.
Endpoints exposed via default /__/{name}
routes. You can configure your checks as described in the API section above.
Check wiring.yml for additional services.
For reference on wiring go to https://github.com/michael-donat/canister.js
Those can be added by either using your the API or tagging services with before.router
and after.router
.
const Microbe = require('uw-microbe.js');
const system = new Microbe(__dirname);
system.configure('./wiring.yml');
system.build();
system.router.get('/', (req, res) => {
res.json({ok: true});
})
system.pre.use((req, res, next) => {
console.log('Some preware');
next();
});
system.start(3321);
It is possible to define startup and shutdown methods via container configuration. Microbe exposes bootstrap
and teardown
methods to trigger the behaviour.
Definition:
components:
mysql:
module: './mysql'
tags:
system.start: ~
redis:
module: './redis'
tags:
system.start: 2
mongo:
class: './mongo'
tags:
system.start: {method: start, priority: 3}
system.stop: {method: stop}
myssql
will be with priority 0 and the startup method will be the one returned from the module (require('./mysql')()
)redis
will be started with priority 2 and the startup method will be the one returned from the module (as above)mongo
will be started with priority 3 and the startup method will bestart
executed inmongo
context (no constructor manual needed,this
will bemongo
)mongo
will shutdown with priority 0 (reverse order), method isstop
bound tomongo
Order is NOT guaranteed if two services have the same priority.
Start/Stop methods are executed in series, always.
Provided start/stop methods are required to return a promise.
Where a start/stop method rejects the entire chain will be rejected.
Microbe can monitor your infrastructure connections and have state pumped onto logger, instrumentation and health endpoints.
There are only two types of events recognised, connect
and disconnect
and any instance provided for monitoring is required to raise those.
Patch methods for redis and mongo are available and will translate events to the required pair. The endpoint patch method will translate available
and unavailable
events.
Definition:
components:
redis:
module: './redis'
tags:
system.start: 2
system.monitor:
type: redis
prop: cache
initiallyConnected: true
mongo:
class: './mongo'
tags:
system.start: {method: start, priority: 3}
system.stop: {method: stop}
system.monitor:
type: mongo
prop: db
required: true
initiallyConnected: true
Syntax:
type
- optional, endpoint, redis or mongo, if left blank it will try to monitor connect/disconnect events on passed instanceprop
- optional, the prop of the service where the events are emitted from, this is required because we often have wrappers around connection objectsname
- optional, arbitrary name, will be used as label in any output type - defaults to component definition id (service name)required
- optional, if set to true and connection is down it will report system as unhealthy in health checks, default is falseinitiallyConnected
- optional, it will set the probe to connected after creation, this is because a lot of the connection objects do not emit connection events, default is true
HTTP endpoint monitoring is available via the https://github.com/utilitywarehouse/uw-lib-endpoint-monitor.js package - please refer to the package documentation for specifics.
Definition:
components:
someApi:
factory: 'axios.create'
with:
- baseURL: 'http://api.example.com'
endpoint.monitor.someAPI:
factory: '@utilitywarehouse/uw-lib-endpoint-monitor.js'
with:
- client: '@someApi'
tags:
system.monitor:
type: endpoint
name: someApi
It is possible to inject values into the container definition before the system is built. This technique should be used during testing only.
const Microbe = require('uw-microbe.js');
const system = new Microbe(__dirname);
system.configure('./wiring.yml');
system.di.inject('my.id', new Object('oi!'));
system.build();
Microbe
✓ sets up default instrumentation
✓ renders errors with error.status and error.message only with http status matching error.status
✓ renders 500/Internal Server Error when no error.status / error.message
✓ can run before() and after() middleware
exposes operational endpoints at
✓ /__/about
✓ /__/ready
✓ /__/health
✓ /__/metrics
provides a logger that
✓ is namespaced with app name
✓ attaches to req.logger with correlation id (id) and request id (r)
✓ logs requests
✓ logs errors with stacks and previous errors