health-check-services
v2.2.6
Published
A library for health check monitoring and runtime measurement
Downloads
654
Maintainers
Readme
Health Check Services
Overview
This package provides comprehensive health check functionality for monitoring the status of various services in your system. It includes:
- Health Check Functions: Monitor service availability by running corresponding health check functions
- AWS Secrets Manager Integration: Securely load environment variables from AWS Secrets Manager with caching
- Service Status Monitoring: Each service returns
true,null,undefined, orvoidto indicate UP status, orfalse/throws error for DOWN status
This is useful for monitoring the health of essential components in your application, such as databases, third-party APIs, internal services, and managing secure configuration through AWS Secrets Manager.
Installation
Install the package using npm:
npm install health-check-servicesOr with Yarn:
yarn add health-check-services
AWS Secrets Manager Integration
Overview
The loadSecrets function provides secure integration with AWS Secrets Manager to load environment variables into your application. It includes intelligent caching to minimize API calls and improve performance.
Prerequisites
Before using loadSecrets, ensure you have:
- AWS Credentials: Configured via AWS CLI, IAM roles, or environment variables
- Required Environment Variables:
SECRET_ID: The name or ARN of the secret in AWS Secrets ManagerAWS_REGION: The AWS region where your secret is stored
- IAM Permissions: Your AWS credentials must have
secretsmanager:GetSecretValuepermission for the specified secret
Environment Variables
Required:
SECRET_ID- The name or ARN of the secret in AWS Secrets ManagerAWS_REGION- The AWS region where your secret is storedAWS_ACCESS_KEY_ID- AWS access key IDAWS_SECRET_ACCESS_KEY- AWS secret access key
Optional:
NODE_ENV- Set to "local" to skip AWS secrets loading
# Required
export SECRET_ID="your-secret-name-or-arn"
export AWS_REGION="us-east-1"
export AWS_ACCESS_KEY_ID="your-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-secret-access-key"
# Optional
export NODE_ENV="local" # Skips AWS secrets loadingUsage
Basic Usage
import { loadSecrets } from 'health-check-services';
// Load secrets at application startup
await loadSecrets();
// Now your environment variables are available
console.log(process.env.DATABASE_URL);
console.log(process.env.API_KEY);Advanced Usage with Options
import { loadSecrets } from 'health-check-services';
// Silent mode - no console output
await loadSecrets({ silent: true });
// Throw errors instead of logging warnings (for strict error handling)
try {
await loadSecrets({ throwOnError: true });
} catch (error) {
console.error('Failed to load secrets:', error.message);
}Integration with Application Startup
import { loadSecrets } from 'health-check-services';
async function startApplication() {
try {
// Load secrets before initializing services
await loadSecrets();
// Initialize your application services
await initializeDatabase();
await startServer();
console.log('Application started successfully');
} catch (error) {
console.error('Failed to start application:', error);
process.exit(1);
}
}
startApplication();Safe Integration (Recommended)
import { loadSecrets } from 'health-check-services';
async function startApplication() {
// Load secrets - this will not crash your app if AWS is not configured
await loadSecrets();
// Your application continues running regardless of secrets loading success
await initializeServices();
await startServer();
console.log('Application started');
}
startApplication();Features
- Intelligent Caching: Secrets are cached for 5 minutes to reduce AWS API calls
- Automatic Environment Variable Assignment: Loaded secrets are automatically assigned to
process.env - Graceful Error Handling: Logs warnings instead of throwing errors by default
- Flexible Configuration: Optional parameters for silent mode and strict error handling
- 🔍 Health Check Integration: Secrets loading status is automatically included in health checks
- TypeScript Support: Full TypeScript definitions included
Secret Format
Your AWS Secrets Manager secret should contain a JSON object with key-value pairs:
{
"DATABASE_URL": "postgresql://user:password@host:port/database",
"API_KEY": "your-api-key-here",
"JWT_SECRET": "your-jwt-secret",
"REDIS_URL": "redis://localhost:6379"
}Error Handling
The function is designed to be resilient and will not crash your application. By default, it logs warnings instead of throwing errors. Here's how different scenarios are handled:
Missing Environment Variables
- SECRET_ID not set: Logs warning and returns gracefully
- AWS_REGION not set: Logs warning and returns gracefully
AWS Configuration Issues
- AWS credentials not configured: Logs warning and returns gracefully
- Insufficient permissions: Logs warning and returns gracefully
- Secret not found: Logs warning and returns gracefully
Data Issues
- Invalid JSON in secret: Logs warning and returns gracefully
- Empty secret returned: Logs warning and returns gracefully
Strict Error Handling (Optional)
If you prefer traditional error handling, use the throwOnError option:
try {
await loadSecrets({ throwOnError: true });
} catch (error) {
console.error('Failed to load secrets:', error.message);
// Handle error appropriately
}Silent Mode (Optional)
To suppress all console output:
await loadSecrets({ silent: true });Health Check Integration
When you use loadSecrets() in your application, the secrets loading status is automatically included in your health check responses. This provides visibility into AWS Secrets Manager connectivity and configuration issues.
Automatic Secrets Monitoring
import { loadSecrets, getHealthCheckStatus } from 'health-check-services';
// Load secrets at startup
await loadSecrets();
// Later, when checking health status
const healthStatus = await getHealthCheckStatus({
database: () => checkDatabaseConnection(),
redis: () => checkRedisConnection(),
});
// The response will automatically include secrets status if loadSecrets was called
console.log(healthStatus.services.secrets);Example Health Check Response with Secrets Status
{
"runtimeMs": 45,
"timestamp": "2025-01-03T12:00:00Z",
"status": "DOWN",
"services": {
"database": {
"timestamp": "2025-01-03T12:00:00Z",
"runtimeMs": 10,
"status": "UP"
},
"redis": {
"timestamp": "2025-01-03T12:00:01Z",
"runtimeMs": 15,
"status": "UP"
},
"secrets": {
"timestamp": "2025-01-03T12:00:02Z",
"runtimeMs": 0,
"status": "DOWN",
"error": "AWS_REGION environment variable is not set. Skipping secrets loading.",
"details": {
"lastErrorTime": "2025-01-03T12:00:02Z",
"errorAgeMs": 5000,
"totalAttempts": 3,
"successfulLoads": 0,
"successRate": "0.0%"
}
}
}
}Secrets Health Check Details
The secrets health check provides detailed information:
- Status:
UPif secrets are loaded successfully or cached,DOWNif there are recent errors - Error: The last error message from
loadSecrets - Details: Additional metrics including:
lastErrorTime: When the last error occurrederrorAgeMs: How long ago the error occurredtotalAttempts: Total number ofloadSecretscallssuccessfulLoads: Number of successful loadssuccessRate: Percentage of successful loadshasCachedSecrets: Whether secrets are currently cachedlastSuccessTime: When secrets were last loaded successfully
Controlling Secrets Health Check Visibility
By default, secrets status is included if loadSecrets has been called. You can control this behavior:
// Include secrets status even if DOWN
const healthStatus = await getHealthCheckStatus({
database: () => checkDatabaseConnection(),
}, { secrets: 1 });
// Exclude secrets status (secrets won't appear in response)
const healthStatus = await getHealthCheckStatus({
database: () => checkDatabaseConnection(),
}, { secrets: 0 });Performance Considerations
- Caching: Secrets are cached for 5 minutes (300,000ms) to minimize AWS API calls
- Concurrent Calls: Multiple simultaneous calls to
loadSecrets()will share the same cache - Memory Usage: Cached secrets are stored in memory, consider secret size implications
Local Development Setup
Quick Setup for Local Development
Set NODE_ENV=local to automatically skip AWS secrets loading:
# Set environment variable
export NODE_ENV=local
# Or in your .env file
NODE_ENV=local
# Or when running
NODE_ENV=local npm run devWhen NODE_ENV=local, loadSecrets() will:
- Skip AWS Secrets Manager calls entirely
- Log:
[loadSecrets] Skipping AWS secrets loading in local/development environment - Return without errors
Usage
Step 1: Load Secrets (Optional but Recommended)
Before defining health check functions, consider loading secrets from AWS Secrets Manager to ensure your services have access to necessary credentials:
import { loadSecrets } from 'health-check-services';
// Load secrets before initializing services
await loadSecrets();Step 2: Define the Health Check Functions for Each Service
Each service in your application must expose a function that will check its health. The function should either:
- Return
true,null,undefined, orvoidto indicate the service is UP. - Return
falseor throw an error to indicate the service is DOWN.
Example Service Health Check Functions:
class DatabaseService {
async checkDatabaseHealth(): Promise<boolean | void> {
// Logic to check the database health (e.g., a query to check connectivity)
return true; // Indicates that the database is UP
}
async otherservice(): Promise<boolean | void> {
// Logic to check the other service health
return false; // Indicates that this service is DOWN
}
}Step 3: Call getHealthCheckStatus Function
The getHealthCheckStatus function is the main entry point for performing the health checks. It takes an object where the key is the service name and the value is the corresponding health check function.
Example Usage of getHealthCheckStatus:
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
});
return healthCheckResponses;The getHealthCheckStatus function returns an object containing the health check status of all services.
Step 4: Customize Service Health Checks
You can easily add additional services by adding new key-value pairs to the input object of getHealthCheckStatus. Each key should be a service name, and the value should be a function that performs the health check for that service.
Example with Additional Service:
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
paymentGateway: () => this.paymentGatewayService.checkHealth(),
});
return healthCheckResponses;Response Structure
The getHealthCheckStatus function returns an object with the following properties:
runtimeMs: The total runtime in milliseconds of all health checks.timestamp: The timestamp of when the health check was performed.status: The overall status of the system ('UP'or'DOWN').services: An object containing the health check responses for each service. Each key is the service name, and the value is ahealthCheckStatusRespTypeobject.
Each healthCheckStatusRespType Object Contains:
timestamp: The timestamp when the health check was performed.runtimeMs: The runtime of the individual service check in milliseconds.status: The status of the service ('UP'or'DOWN').error: Any error that occurred during the health check, if applicable.
Example Response:
{
"runtimeMs": 50,
"timestamp": "2025-01-03T12:00:00Z",
"status": "UP",
"services": {
"database": {
"timestamp": "2025-01-03T12:00:00Z",
"runtimeMs": 10,
"status": "UP"
},
"otherservice": {
"timestamp": "2025-01-03T12:00:01Z",
"runtimeMs": 20,
"status": "DOWN",
"error": "Service unavailable"
},
"paymentGateway": {
"timestamp": "2025-01-03T12:00:02Z",
"runtimeMs": 15,
"status": "UP"
}
}
}Error Handling
If any service health check function throws an error or returns false, the status for that service will be marked as DOWN. The error will be captured and displayed in the response under the error field.
Optional Query Parameter
You can pass an optional query parameter to the getHealthCheckStatus function, which is a record of service names and their respective statuses. If the status of a service is set to 1 in the query, the status will be shown as part of the response even if it's DOWN. If not specified, only the UP services are shown by default.
Example with Query Parameter:
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
}, { otherservice: 1 });
return healthCheckResponses;Complete Integration Example
Here's a complete example showing how to integrate both loadSecrets and health checks in a real application:
import express from 'express';
import { loadSecrets, getHealthCheckStatus } from 'health-check-services';
class ApplicationServices {
async checkDatabaseHealth(): Promise<boolean> {
// Use environment variables loaded from AWS Secrets Manager
const dbUrl = process.env.DATABASE_URL;
if (!dbUrl) throw new Error('Database URL not configured');
// Your database health check logic here
return true; // or false if unhealthy
}
async checkRedisHealth(): Promise<boolean> {
const redisUrl = process.env.REDIS_URL;
if (!redisUrl) throw new Error('Redis URL not configured');
// Your Redis health check logic here
return true;
}
async checkExternalAPI(): Promise<boolean> {
const apiKey = process.env.EXTERNAL_API_KEY;
if (!apiKey) throw new Error('API key not configured');
// Your external API health check logic here
return true;
}
}
async function startApplication() {
const app = express();
const services = new ApplicationServices();
try {
// Step 1: Load secrets from AWS Secrets Manager
console.log('Loading secrets from AWS Secrets Manager...');
await loadSecrets();
console.log('Secrets loaded successfully');
// Step 2: Initialize your services
await services.initialize();
// Step 3: Set up health check endpoint
app.get('/health-check', async (req, res) => {
try {
const healthStatus = await getHealthCheckStatus({
database: () => services.checkDatabaseHealth(),
redis: () => services.checkRedisHealth(),
externalAPI: () => services.checkExternalAPI(),
});
// The response will automatically include 'secrets' status if loadSecrets was called
// This provides visibility into AWS Secrets Manager connectivity issues
res.status(200).json(healthStatus);
} catch (error) {
res.status(500).json({
error: 'Health check failed',
details: error.message
});
}
});
// Step 4: Start the server
app.listen(3000, () => {
console.log('Server is running on port 3000');
console.log('Health check available at http://localhost:3000/health-check');
});
} catch (error) {
console.error('Failed to start application:', error);
process.exit(1);
}
}
startApplication();Adding the Health Check Functionality to a Server
To make the health check functionality available as an API endpoint, you can create a GET route on your server. For example, you can add a /health-check endpoint to expose the health status.
Step 1: Create the Health Check Endpoint
Add the following route to your server:
Example with Express.js:
import express from 'express';
import getHealthCheckStatus from 'health-check-services';
const app = express();
app.get('/health-check', async (req, res) => {
try {
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
});
res.status(200).json(healthCheckResponses);
} catch (error) {
res.status(500).json({ error: 'Health check failed', details: error });
}
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});Step 2: Test the Endpoint
Start your server and navigate to http://HOST.com/health-check in your browser or API testing tool. You should see a JSON response with the health status of all configured services.
Step 3: Add Additional Services
To monitor more services, simply extend the object passed to getHealthCheckStatus with additional key-value pairs representing the service name and its health check function.
Example:
app.get('/health-check', async (req, res) => {
try {
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
paymentGateway: () => this.paymentGatewayService.checkHealth(),
});
res.status(200).json(healthCheckResponses);
} catch (error) {
res.status(500).json({ error: 'Health check failed', details: error });
}
});Conclusion
This health check function is a powerful tool for monitoring the availability of critical services in your system. By adding the relevant service health check functions, you can quickly determine which services are operational and which need attention. The flexible input and output structures make it easy to integrate into various systems and expand to new services.
