@ahmedhegazee/nestjs-telescope
Version:
Advanced observability and monitoring solution for NestJS applications with ML-powered analytics, enterprise features, and production-ready scaling
207 lines • 8.9 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var StorageManagerService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageManagerService = void 0;
const common_1 = require("@nestjs/common");
const memory_storage_driver_1 = require("./drivers/memory-storage.driver");
const file_storage_driver_1 = require("./drivers/file-storage.driver");
const redis_storage_driver_1 = require("./drivers/redis-storage.driver");
let StorageManagerService = StorageManagerService_1 = class StorageManagerService {
constructor(config) {
this.config = config;
this.logger = new common_1.Logger(StorageManagerService_1.name);
this.drivers = new Map();
this.healthStatus = new Map();
}
async onModuleInit() {
await this.initializeDrivers();
this.startHealthChecks();
}
async initializeDrivers() {
try {
this.drivers.set('memory', new memory_storage_driver_1.MemoryStorageDriver());
this.drivers.set('file', new file_storage_driver_1.FileStorageDriver(this.config.storage));
this.drivers.set('redis', new redis_storage_driver_1.RedisStorageDriver(this.config.storage));
const primaryDriverName = this.config.storage.driver;
this.primaryDriver = this.drivers.get(primaryDriverName);
if (!this.primaryDriver) {
this.logger.warn(`Primary driver '${primaryDriverName}' not available, falling back to memory`);
this.primaryDriver = this.drivers.get('memory');
}
const fallbackDriverName = this.config.storage.fallback;
if (fallbackDriverName && fallbackDriverName !== primaryDriverName) {
this.fallbackDriver = this.drivers.get(fallbackDriverName);
if (!this.fallbackDriver) {
this.logger.warn(`Fallback driver '${fallbackDriverName}' not available`);
}
}
this.logger.log(`Storage manager initialized with primary: ${primaryDriverName}, fallback: ${fallbackDriverName || 'none'}`);
await this.checkAllDriversHealth();
}
catch (error) {
this.logger.error('Failed to initialize storage drivers:', error);
throw error;
}
}
async store(entry) {
return this.executeWithFallback(async () => {
await this.primaryDriver.store(entry);
this.logger.debug(`Stored entry ${entry.id} with primary driver`);
}, async () => {
if (this.fallbackDriver) {
await this.fallbackDriver.store(entry);
this.logger.debug(`Stored entry ${entry.id} with fallback driver`);
}
}, 'store');
}
async storeBatch(entries) {
return this.executeWithFallback(async () => {
await this.primaryDriver.storeBatch(entries);
this.logger.debug(`Stored batch of ${entries.length} entries with primary driver`);
}, async () => {
if (this.fallbackDriver) {
await this.fallbackDriver.storeBatch(entries);
this.logger.debug(`Stored batch of ${entries.length} entries with fallback driver`);
}
}, 'storeBatch');
}
async find(filter) {
return this.executeWithFallback(() => this.primaryDriver.find(filter), () => this.fallbackDriver?.find(filter), 'find');
}
async findById(id) {
return this.executeWithFallback(() => this.primaryDriver.findById(id), () => this.fallbackDriver?.findById(id), 'findById');
}
async delete(id) {
return this.executeWithFallback(() => this.primaryDriver.delete(id), () => this.fallbackDriver?.delete(id), 'delete');
}
async clear() {
return this.executeWithFallback(() => this.primaryDriver.clear(), () => this.fallbackDriver?.clear(), 'clear');
}
async prune(olderThan) {
return this.executeWithFallback(() => this.primaryDriver.prune(olderThan), () => this.fallbackDriver?.prune(olderThan), 'prune');
}
async getStats() {
return this.executeWithFallback(() => this.primaryDriver.getStats(), () => this.fallbackDriver?.getStats(), 'getStats');
}
async executeWithFallback(primary, fallback, operation) {
try {
const result = await primary();
return result;
}
catch (error) {
this.logger.warn(`Primary storage failed for ${operation}: ${error.message}`);
if (fallback) {
try {
const result = await fallback();
this.logger.log(`Fallback storage succeeded for ${operation}`);
return result;
}
catch (fallbackError) {
this.logger.error(`Fallback storage failed for ${operation}: ${fallbackError.message}`);
throw error;
}
}
throw error;
}
}
async checkAllDriversHealth() {
for (const [name, driver] of this.drivers) {
try {
const isHealthy = await this.checkDriverHealth(driver);
this.healthStatus.set(name, isHealthy);
if (isHealthy) {
this.logger.debug(`Driver '${name}' is healthy`);
}
else {
this.logger.warn(`Driver '${name}' is unhealthy`);
}
}
catch (error) {
this.logger.error(`Health check failed for driver '${name}':`, error);
this.healthStatus.set(name, false);
}
}
}
async checkDriverHealth(driver) {
try {
if ('healthCheck' in driver && typeof driver.healthCheck === 'function') {
return await driver.healthCheck();
}
await driver.getStats();
return true;
}
catch (error) {
return false;
}
}
startHealthChecks() {
setInterval(async () => {
await this.checkAllDriversHealth();
}, 30000);
}
getDriverHealth() {
return Object.fromEntries(this.healthStatus);
}
async getDetailedStats() {
const stats = await this.getStats();
return {
primary: this.config.storage.driver,
fallback: this.config.storage.fallback,
health: this.getDriverHealth(),
stats
};
}
getPrimaryDriver() {
return this.primaryDriver;
}
getFallbackDriver() {
return this.fallbackDriver;
}
getAvailableDrivers() {
return Array.from(this.drivers.keys());
}
async switchPrimaryDriver(driverName) {
const newDriver = this.drivers.get(driverName);
if (!newDriver) {
throw new Error(`Driver '${driverName}' not available`);
}
const isHealthy = await this.checkDriverHealth(newDriver);
if (!isHealthy) {
throw new Error(`Driver '${driverName}' is not healthy`);
}
this.primaryDriver = newDriver;
this.logger.log(`Switched primary driver to: ${driverName}`);
}
async cleanup() {
for (const [name, driver] of this.drivers) {
try {
if ('cleanup' in driver && typeof driver.cleanup === 'function') {
await driver.cleanup();
this.logger.debug(`Cleaned up driver: ${name}`);
}
}
catch (error) {
this.logger.error(`Failed to cleanup driver '${name}':`, error);
}
}
}
};
exports.StorageManagerService = StorageManagerService;
exports.StorageManagerService = StorageManagerService = StorageManagerService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, common_1.Inject)('TELESCOPE_CONFIG')),
__metadata("design:paramtypes", [Object])
], StorageManagerService);
//# sourceMappingURL=storage-manager.service.js.map