@duongtrungnguyen/nestro
Version:
Service registry for Nest JS
157 lines • 6.51 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
var discovery_service_exports = {};
__export(discovery_service_exports, {
DiscoveryService: () => DiscoveryService
});
module.exports = __toCommonJS(discovery_service_exports);
var import_common = require("@nestjs/common");
var import_common2 = require("../../common");
var import_constants = require("../constants");
var import_errors = require("../errors");
var import_loadbalancing = require("../loadbalancing");
var import_client = require("../../client");
let DiscoveryService = class {
constructor(loadBalancingConfigs, loadBalancer, serverInfo) {
this.loadBalancingConfigs = loadBalancingConfigs;
this.loadBalancer = loadBalancer;
this.services = /* @__PURE__ */ new Map();
this.serverBaseUrl = (0, import_common2.getServerURL)(serverInfo);
}
async onModuleInit() {
(0, import_common2.debugLog)(DiscoveryService.name, "Initializing DiscoveryService...");
await this.loadInstances();
this.refreshIntervalId = setInterval(() => this.loadInstances(), this.loadBalancingConfigs.refreshInterval);
}
onModuleDestroy() {
if (this.refreshIntervalId) {
clearInterval(this.refreshIntervalId);
}
(0, import_common2.debugLog)(DiscoveryService.name, "DiscoveryService stopped");
}
/**
* Refreshes the service registry by fetching the latest instances from the server
*/
async loadInstances() {
(0, import_common2.debugLog)(DiscoveryService.name, "Refreshing service registry");
try {
const response = await fetch(`${this.serverBaseUrl}/nestro/services`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
});
if (!response.ok) {
throw new Error(`Failed to fetch services: ${response.statusText}`);
}
const services = await response.json();
this.services.clear();
Object.entries(services).forEach(([serviceName, instances]) => {
const activeInstances = instances.filter((instance) => instance.status === "ON");
if (activeInstances.length > 0) {
this.services.set(serviceName, activeInstances);
}
});
(0, import_common2.debugLog)(DiscoveryService.name, `Registry refreshed with ${this.services.size} services`);
} catch (error) {
(0, import_common2.debugError)(DiscoveryService.name, `Failed to refresh registry: ${error.message}`);
}
}
getServices() {
return this.services;
}
/**
* Gets all instances for a specific service
*/
getInstances(serviceName) {
return this.services.get(serviceName) || [];
}
async discover(serviceName, callback) {
const instances = this.getInstances(serviceName);
if (!instances || instances.length === 0) {
throw new import_errors.DiscoveryError(`Service ${serviceName} not found in registry`, import_errors.DiscoveryErrorCode.SERVICE_NOT_FOUND);
}
let lastError = null;
const attemptedInstances = /* @__PURE__ */ new Set();
const maxRetries = instances.length;
for (let attempt = 0; attempt < maxRetries; attempt++) {
const remainingInstances = instances.filter((instance) => !attemptedInstances.has(this.getInstanceId(instance)));
if (remainingInstances.length === 0) {
break;
}
const selectedInstance = this.loadBalancer.selectInstance(remainingInstances);
if (!selectedInstance) {
break;
}
const instanceId = this.getInstanceId(selectedInstance);
attemptedInstances.add(instanceId);
if (this.loadBalancer.trackConnectionStart) {
this.loadBalancer.trackConnectionStart(instanceId);
}
const startTime = Date.now();
let shouldRetry = false;
const tryAnotherInstance = async () => {
attemptedInstances.add(this.getInstanceId(selectedInstance));
if (this.loadBalancer.trackConnectionEnd) {
this.loadBalancer.trackConnectionEnd(instanceId);
}
shouldRetry = true;
};
try {
const result = await callback(selectedInstance, tryAnotherInstance);
if (this.loadBalancer instanceof import_loadbalancing.ResponseTimeStrategy) {
const responseTime = Date.now() - startTime;
this.loadBalancer.recordResponseTime(instanceId, responseTime);
}
if (!shouldRetry) {
return result;
}
} catch (error) {
if (!shouldRetry) {
throw error;
}
}
}
if (lastError) throw lastError;
throw new import_errors.DiscoveryError(`All instances for ${serviceName} service failed`, import_errors.DiscoveryErrorCode.ALL_INSTANCES_FAILED);
}
getInstanceId(instance) {
return `${instance.name}:${instance.host}:${instance.port}`;
}
};
DiscoveryService = __decorateClass([
(0, import_common.Injectable)(),
__decorateParam(0, (0, import_common.Inject)(import_constants.LOAD_BALANCING_CONFIGS)),
__decorateParam(1, (0, import_common.Inject)(import_constants.LOAD_BALANCER)),
__decorateParam(2, (0, import_common.Inject)(import_client.SERVER_INFO))
], DiscoveryService);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DiscoveryService
});
//# sourceMappingURL=discovery.service.js.map