@gati-framework/runtime
Version:
Gati runtime execution engine for running handler-based applications
116 lines • 4.14 kB
JavaScript
/**
* @module runtime/coordinators/consul-coordinator
* @description Consul-based lifecycle coordinator for service discovery and health management
*/
/**
* Consul-based lifecycle coordinator
*/
export class ConsulCoordinator {
config;
shutdownHandlers = [];
constructor(config) {
this.config = config;
}
/**
* Register service with Consul
*/
async register() {
const serviceDefinition = {
ID: this.config.serviceId,
Name: this.config.serviceName,
Port: this.config.servicePort,
Tags: this.config.tags || [],
Check: {
HTTP: `http://localhost:${this.config.servicePort}${this.config.healthCheckPath}`,
Interval: this.config.healthCheckInterval,
Timeout: '10s',
DeregisterCriticalServiceAfter: '30s',
},
};
try {
const response = await fetch(`http://${this.config.host}:${this.config.port}/v1/agent/service/register`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(serviceDefinition),
});
if (!response.ok) {
throw new Error(`Failed to register service: ${response.statusText}`);
}
console.log(`✅ Service registered with Consul: ${this.config.serviceId}`);
}
catch (error) {
console.error('❌ Failed to register with Consul:', error);
throw error;
}
}
/**
* Deregister service from Consul
*/
async deregister() {
try {
const response = await fetch(`http://${this.config.host}:${this.config.port}/v1/agent/service/deregister/${this.config.serviceId}`, {
method: 'PUT',
});
if (!response.ok) {
throw new Error(`Failed to deregister service: ${response.statusText}`);
}
console.log(`✅ Service deregistered from Consul: ${this.config.serviceId}`);
}
catch (error) {
console.error('❌ Failed to deregister from Consul:', error);
}
}
/**
* Report health status to Consul
*/
async reportHealth(status) {
const checkStatus = status.status === 'healthy' ? 'pass' :
status.status === 'degraded' ? 'warn' : 'fail';
try {
const response = await fetch(`http://${this.config.host}:${this.config.port}/v1/agent/check/update/service:${this.config.serviceId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Status: checkStatus,
Output: JSON.stringify(status.checks),
}),
});
if (!response.ok) {
throw new Error(`Failed to update health check: ${response.statusText}`);
}
}
catch (error) {
console.warn('Failed to report health to Consul:', error);
}
}
/**
* Listen for coordinated shutdown signals
*/
onCoordinatedShutdown(fn) {
this.shutdownHandlers.push(fn);
process.on('SIGTERM', async () => {
console.log('📡 Received coordinated shutdown signal (SIGTERM)');
for (const handler of this.shutdownHandlers) {
try {
await handler();
}
catch (error) {
console.error('Coordinated shutdown handler failed:', error);
}
}
});
process.on('SIGINT', async () => {
console.log('📡 Received shutdown signal (SIGINT)');
for (const handler of this.shutdownHandlers) {
try {
await handler();
}
catch (error) {
console.error('Shutdown handler failed:', error);
}
}
process.exit(0);
});
}
}
//# sourceMappingURL=consul-coordinator.js.map