@axinom/mosaic-service-common
This package contains modules that help to create a Mosaic-based service.
Configuration management
Microservices have the benefit to be developed independently from each other, potentially with different approaches and technologies. But this can make it quite hard to know and learn about all the different ways and patterns on how to configure each service individually.
The Mosaic configuration management offers a set of common configuration settings and how to load them from the environment variables, validate them, and exposes them inside of Mosaic based applications.
You can pick one of the existing configuration definitions and define your own that you can reuse in your different services. There are utility functions for basic configurations, GraphQL settings, database connections, Rabbit MQ, etc.
Logging and Error handling
There is a common logging solution that encapsulates all the aspects around logging. It includes different log levels and log configurations. It includes a log masking middleware which helps to not write secret values to your log files. To ensure a central handling of those log aspects a global console.log overwrite can be used to route all log messages to this logging logic.
The library offers utilities that help you with consistent error handling. It has different classes that inherit from the base JavaScript Error class and provide additional functionality. It includes specific error handlers e.g. mappings for PostgreSQL database error codes.
Health Monitoring
The following section describes the helper functions that are exported through this library and their usage.
setupLivenessAndReadiness
When your services are deployed with Axinom Hosting or when you self-host with the help of a container orchestration layer (i.e. k8s), it will be essential to expose liveness & readiness endpoints that can be probed by the hosting layer for ensuring appropriate steps are taken when the service goes through different life-cycles.
Liveness probe
Liveness probes determine when to restart a service. For example, liveness probes could be used when a service enters a deadlock while it's running and is unable to make progress or auto-heal. If a service sets its liveness probe to false
, it will be restarted.
Readiness probe
Readiness probes determine when a service is ready to start accepting traffic. This is useful when waiting for the service to perform time-consuming boot-up sequence tasks, such as establishing network connections, loading files, and warming caches. Until the service will set its readiness to true, it will not receive any traffic.
Usage
The function signature is given below.
setupLivenessAndReadiness = (
config: BasicConfig,
livenessReadinessOptions: ILivenessReadinessOptions = {},
logger?: Logger,
): {
liveness: State<boolean>;
readiness: State<boolean>;
}
The table below describes the arguments in the function signature.
Parameter | Description |
---|---|
config | The config object of the service. |
livenessReadinessOptions | This parameter is an optional object that is used to configure the liveness & readiness default behaviors. |
logger | This is an optional parameter that can be used to pass a logging utility.. |
This function is called at the service start-up, typically from the index.ts
of the service. Then the service can use the liveness
& readiness
return values to control the behavior as necessary. It will create an express app that listens on the port that's configured on config.healthEndpointPort
, which is 9000
by default.
You could change the readiness
of your service by calling readiness.setState(true)
after your service has gone through the boot-up sequence.
You could change the liveness
at any point using some custom asynchronous/event based logic by calling liveness.setState(false)
. For example, if your service is stuck in an unrecoverable state due to a deadlock situation, it could call the liveness.setState(false)
method and let the container orchestration layer detect that on the next liveness probing and automatically restart the container to potentially fix the deadlock issue.
setupServiceHealthEndpoint
This sets up a health endpoint for an express application. The serviceHealthOptions
object will contain the options to configure the health endpoint route as required, and if not specified, will default to /health
.
The function will return a serviceHealthData
handle, that can be used to set the current health data of the service (i.e. a key-value object as defined by the service). If not set, this will default to an empty object.
When an HTTP GET request is made to the health endpoint of a service, it will return a 200 response code along with contents set to the serviceHealthData
handle by the service.
This is different from the setupLivenessAndReadiness
helper described above. The setupLivenessAndReadiness
is used internally by the container orchestration layer (such as k8s) to automatically react to service life-cycle changes. Where-as setupServiceHealthEndpoint
is meant to expose a publicly accessible route that provides a Key-Value pair object
to indicate the current running state of your service in a much more granular way that can be used in further monitoring tools and integrations as necessary.
Usage
The function signature is given below.
const setupServiceHealthEndpoint = (
app: Express,
ServiceHealthEndpointOptions: ServiceHealthEndpointOptions = {},
logger?: Logger,
): {
serviceHealthData: HealthData;
}
The table below describes the arguments in the function signature.
Parameter | Description |
---|---|
app | Instance of the Express application. |
ServiceHealthEndpointOptions | This parameter is an optional object that is used to configure options related to the service health endpoint. |
logger | This is an optional parameter that can be used to pass a logging utility.. |
This function is called at the service start-up, typically from the index.ts
of the service.
isServiceAvailable
This function is used to check the health status of a service by accessing the /health
endpoint.
The function returns a Promise<boolean> indicating whether the service is available. It check the availability of a service by making HTTP requests to the specified URL and route and returning true if the service is available and false otherwise.
Usage
The function signature is shown below.
const isServiceAvailable = async (
baseUrl: string,
healthRoute = '/health',
maxRetryAttempts = 15,
logger?: Logger,
): Promise<boolean>
The table below describes the arguments in the isServiceAvailable
function.
Parameter | Description |
---|---|
baseUrl | The base URL of the service.. |
healthRoute | The path to mount the service health endpoint. If not specified, will default to /health . |
maxRetryAttempts | The maximum number of retry attempts when checking the service’s availability, default count will be 15. |
logger | A logger object to use for output generated inside the middleware. |
This function is called at the service start-up, typically from the index.ts
of the service.
Utilities
In addition to the above mentioned modules, this library includes a lot of other utility modules. Those are about type definitions, unit testing helpers, seed data generation, and a lot more.