Add moment.js as a dependency, enhance TypeScript configuration to exclude scripts, and introduce new examples for dependency injection and health checks.

This commit is contained in:
2025-10-26 09:39:46 -04:00
parent 5d9b77ef7d
commit 3429df650f
26 changed files with 868 additions and 30 deletions

143
src/health/HealthCheck.ts Normal file
View File

@@ -0,0 +1,143 @@
import moment from 'moment';
import type IDisposable from '../lang/IDisposable';
import {Events} from '../lang/Events';
const checkForRecoverabilityTimeout = moment.duration(30, 'seconds');
interface IHealthCheckable {
checkForRecoverability(): Promise<boolean>;
}
export class HealthCheck {
private readonly _environment: string;
private readonly _app: string;
private readonly _version: string;
private readonly _regionName: string;
private readonly _zone: string;
private readonly _checks: IHealthCheckable[];
private readonly _since: string;
private readonly _events: Events;
private _status: string;
private _enabled: boolean;
constructor(environment: string, app: string, version: string, regionName: string, zone: string, ...checkForRecoverability: IHealthCheckable[]) {
this._environment = environment;
this._app = app;
this._version = version;
this._regionName = regionName;
this._zone = zone;
this._checks = checkForRecoverability;
this._since = moment.utc().toISOString();
this._status = 'starting';
this._events = new Events();
this._enabled = true;
}
public start() {
this._status = 'starting';
this._events.emit('starting');
this._events.emit('status-changed');
return null;
}
public getInfo() {
return {
environment: this._environment,
app: this._app,
version: this._version,
region: this._regionName,
zone: this._zone,
since: this._since
};
}
public async checkHealth() {
if (this._status !== 'ok') {
return {
status: this._status,
environment: this._environment,
app: this._app,
version: this._version,
zone: this._zone
};
}
try {
const results = await Promise.all(
this._checks.map(async check => {
const isHealthy = await check.checkForRecoverability();
if (!isHealthy) {
console.warn('Health check failed [%s]', check);
} else {
console.debug('Health check passed [%s]', check);
}
return isHealthy;
})
);
const success = results.every(result => result === true);
if (success === true) {
let status = this._status;
if (status === 'ok' && !this._enabled) {
status = 'disabled';
}
return {
status,
environment: this._environment,
app: this._app,
version: this._version,
zone: this._zone
};
}
this._events.emit('health-check-failed');
return {
status: 'health-check-failed',
environment: this._environment,
app: this._app,
version: this._version,
zone: this._zone
};
} catch (e) {
this._events.emit('health-check-failed');
console.warn('Health check failed', e);
return {
status: 'health-check-failed',
environment: this._environment,
app: this._app,
version: this._version,
zone: this._zone,
reason: (e as Error).message
};
}
}
public on(event: string, listener: (...args: unknown[]) => void | Promise<void>): IDisposable {
return this._events.on(event, listener);
}
public markReady() {
this._status = 'ok';
this._events.emit('ok');
this._events.emit('status-changed');
return null;
}
public enable(): void {
this._enabled = true;
}
public disable(): void {
this._enabled = false;
}
}