A library for health check monitoring and runtime measurement
npm install health-check-services- 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, or void to indicate UP status, or false/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.
Install the package using npm:
``bash`
npm install health-check-services
Or with Yarn:
`bash
yarn add health-check-services
`
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.$3
Before using loadSecrets, ensure you have:1. AWS Credentials: Configured via AWS CLI, IAM roles, or environment variables
2. Required Environment Variables:
-
SECRET_ID: The name or ARN of the secret in AWS Secrets Manager
- AWS_REGION: The AWS region where your secret is stored
3. IAM Permissions: Your AWS credentials must have secretsmanager:GetSecretValue permission for the specified secret$3
Required:
-
SECRET_ID - The name or ARN of the secret in AWS Secrets Manager
- AWS_REGION - The AWS region where your secret is stored
- AWS_ACCESS_KEY_ID - AWS access key ID
- AWS_SECRET_ACCESS_KEY - AWS secret access keyOptional:
-
NODE_ENV - Set to "local" to skip AWS secrets loading`bash
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 loading
`$3
#### Basic Usage
`typescript
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
`typescript
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
`typescript
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)
`typescript
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();
`$3
- 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$3
Your AWS Secrets Manager secret should contain a JSON object with key-value pairs:
`json
{
"DATABASE_URL": "postgresql://user:password@host:port/database",
"API_KEY": "your-api-key-here",
"JWT_SECRET": "your-jwt-secret",
"REDIS_URL": "redis://localhost:6379"
}
`$3
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:`typescript
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:
`typescript
await loadSecrets({ silent: true });
`$3
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
`typescript
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
`json
{
"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:
UP if secrets are loaded successfully or cached, DOWN if there are recent errors
- Error: The last error message from loadSecrets
- Details: Additional metrics including:
- lastErrorTime: When the last error occurred
- errorAgeMs: How long ago the error occurred
- totalAttempts: Total number of loadSecrets calls
- successfulLoads: Number of successful loads
- successRate: Percentage of successful loads
- hasCachedSecrets: Whether secrets are currently cached
- lastSuccessTime: 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:`typescript
// 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 });
`$3
- 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 implicationsLocal Development Setup
$3
Set
NODE_ENV=local to automatically skip AWS secrets loading:`bash
Set environment variable
export NODE_ENV=localOr in your .env file
NODE_ENV=localOr when running
NODE_ENV=local npm run dev
`When
NODE_ENV=local, loadSecrets() will:
- Skip AWS Secrets Manager calls entirely
- Log: [loadSecrets] Skipping AWS secrets loading in local/development environment
- Return without errorsUsage
$3
Before defining health check functions, consider loading secrets from AWS Secrets Manager to ensure your services have access to necessary credentials:
`typescript
import { loadSecrets } from 'health-check-services';// Load secrets before initializing services
await loadSecrets();
`$3
Each service in your application must expose a function that will check its health. The function should either:
- Return
true, null, undefined, or void to indicate the service is UP.
- Return false or throw an error to indicate the service is DOWN.#### Example Service Health Check Functions:
`typescript
class DatabaseService {
async checkDatabaseHealth(): Promise {
// Logic to check the database health (e.g., a query to check connectivity)
return true; // Indicates that the database is UP
}
async otherservice(): Promise {
// Logic to check the other service health
return false; // Indicates that this service is DOWN
}
}
`$3
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:`typescript
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.$3
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:
`typescript
const healthCheckResponses = await getHealthCheckStatus({
database: () => this.databaseService.checkDatabaseHealth(),
otherservice: () => this.databaseService.otherservice(),
paymentGateway: () => this.paymentGatewayService.checkHealth(),
});return healthCheckResponses;
`$3
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 a healthCheckStatusRespType object.#### 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:
`json
{
"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"
}
}
}
`$3
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.$3
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:
`typescript
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:`typescript
import express from 'express';
import { loadSecrets, getHealthCheckStatus } from 'health-check-services';class ApplicationServices {
async checkDatabaseHealth(): Promise {
// 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 {
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 {
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.$3
Add the following route to your server:
#### Example with Express.js:
`typescript
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');
});
`$3
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.$3
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:
`typescript
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 });
}
});
``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.