feat: Mejorar el manejo de errores en el sistema de feature flags con logging detallado y agregar script de depuración
This commit is contained in:
146
README/FEATURE_FLAGS_FIX.md
Normal file
146
README/FEATURE_FLAGS_FIX.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# 🔧 Solución a Errores de Feature Flags
|
||||
|
||||
## ❌ Problema Encontrado
|
||||
|
||||
Los errores mostrados:
|
||||
```
|
||||
[FeatureFlags] Error al setear flag "alianzas_blacklist_31_10_2025":
|
||||
[FeatureFlagsCmd]
|
||||
[FeatureFlags] Error al inicializar:
|
||||
```
|
||||
|
||||
## ✅ Causas Identificadas
|
||||
|
||||
1. **Base de datos vacía**: No había flags iniciales
|
||||
2. **Logger sin detalles**: No mostraba el error completo
|
||||
3. **Posible inicialización incompleta**: Bot intentó usar servicio antes de inicializar
|
||||
|
||||
## 🛠️ Soluciones Aplicadas
|
||||
|
||||
### 1. Mejorado Logging de Errores
|
||||
|
||||
**Archivo**: `src/core/services/FeatureFlagService.ts`
|
||||
- Agregado logging detallado con `message`, `stack`, `code`, `meta`
|
||||
- Ahora muestra errores completos de Prisma
|
||||
|
||||
**Archivo**: `src/core/loaders/featureFlagsLoader.ts`
|
||||
- Logging extendido en múltiples líneas
|
||||
- Muestra cada propiedad del error por separado
|
||||
|
||||
### 2. Creado Script de Debug
|
||||
|
||||
**Archivo**: `scripts/debugFeatureFlags.ts`
|
||||
- Lista todos los flags en DB
|
||||
- Verifica parsing de JSON
|
||||
- Test de creación/eliminación
|
||||
- Muestra detalles completos de cada flag
|
||||
|
||||
### 3. Ejecutado Setup Inicial
|
||||
|
||||
**Comando**: `npx tsx scripts/setupFeatureFlags.ts`
|
||||
|
||||
**Flags creados** (8 ejemplos):
|
||||
- ✅ `new_shop_system` (disabled)
|
||||
- ✅ `inventory_ui_v2` (enabled)
|
||||
- ✅ `improved_combat_algorithm` (rollout 25%)
|
||||
- ✅ `economy_system_v2` (gradual rollout)
|
||||
- ✅ `halloween_2025` (evento temporal)
|
||||
- ✅ `experimental_features` (whitelist)
|
||||
- ✅ `premium_features` (disabled con metadata)
|
||||
- ✅ `trading_system` (maintenance)
|
||||
|
||||
### 4. Verificado Funcionamiento
|
||||
|
||||
**Test realizado**: ✅ Exitoso
|
||||
```bash
|
||||
✅ Servicio inicializado
|
||||
📊 8 flags cargados
|
||||
✅ Todos los flags parseados correctamente
|
||||
```
|
||||
|
||||
## 🚀 Próximos Pasos
|
||||
|
||||
### 1. Reiniciar el Bot
|
||||
```bash
|
||||
# El bot ahora debe inicializar correctamente
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2. Verificar en Discord
|
||||
```
|
||||
/featureflags list
|
||||
```
|
||||
|
||||
### 3. Crear Nuevos Flags
|
||||
```
|
||||
/featureflags create name:mi_feature status:disabled target:global
|
||||
/featureflags update flag:mi_feature status:enabled
|
||||
```
|
||||
|
||||
### 4. Ver Estadísticas
|
||||
```
|
||||
/featureflags stats flag:inventory_ui_v2
|
||||
```
|
||||
|
||||
## 📝 Comandos Útiles
|
||||
|
||||
### Debug Manual
|
||||
```bash
|
||||
# Ver todos los flags en DB
|
||||
npx tsx scripts/debugFeatureFlags.ts
|
||||
|
||||
# Test del servicio
|
||||
npx tsx -e "
|
||||
import { featureFlagService } from './src/core/services/FeatureFlagService';
|
||||
await featureFlagService.initialize();
|
||||
console.log(featureFlagService.getFlags());
|
||||
"
|
||||
```
|
||||
|
||||
### Resetear Flags
|
||||
```bash
|
||||
# Eliminar todos los flags
|
||||
npx tsx -e "
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
const prisma = new PrismaClient();
|
||||
await prisma.featureFlag.deleteMany({});
|
||||
await prisma.\$disconnect();
|
||||
"
|
||||
|
||||
# Recrear flags de ejemplo
|
||||
npx tsx scripts/setupFeatureFlags.ts
|
||||
```
|
||||
|
||||
## 🔍 Debugging Futuro
|
||||
|
||||
Si vuelven a aparecer errores:
|
||||
|
||||
1. **Ejecutar debug script**:
|
||||
```bash
|
||||
npx tsx scripts/debugFeatureFlags.ts
|
||||
```
|
||||
|
||||
2. **Verificar logs mejorados**: Ahora muestran:
|
||||
- `error.message`
|
||||
- `error.stack`
|
||||
- `error.code` (código de Prisma)
|
||||
- `error.meta` (metadata de Prisma)
|
||||
|
||||
3. **Test de conexión**:
|
||||
```bash
|
||||
npx tsx -e "
|
||||
import { prisma } from './src/core/database/prisma';
|
||||
const count = await prisma.featureFlag.count();
|
||||
console.log('Flags en DB:', count);
|
||||
"
|
||||
```
|
||||
|
||||
## ✅ Estado Actual
|
||||
|
||||
- ✅ Tabla `FeatureFlag` creada y sincronizada
|
||||
- ✅ 8 flags de ejemplo en DB
|
||||
- ✅ Servicio funcionando correctamente
|
||||
- ✅ Logging mejorado
|
||||
- ✅ Script de debug disponible
|
||||
|
||||
**El sistema está listo para usar.** 🎮
|
||||
88
scripts/debugFeatureFlags.ts
Normal file
88
scripts/debugFeatureFlags.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Debug del sistema de Feature Flags
|
||||
*/
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function debugFeatureFlags() {
|
||||
console.log("🔍 Debugging Feature Flags...\n");
|
||||
|
||||
try {
|
||||
// Listar todos los flags
|
||||
const flags = await prisma.featureFlag.findMany();
|
||||
console.log(`📊 Total de flags en DB: ${flags.length}\n`);
|
||||
|
||||
if (flags.length === 0) {
|
||||
console.log("ℹ️ No hay flags en la base de datos");
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar cada flag
|
||||
for (const flag of flags) {
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
console.log(`🎯 Flag: ${flag.name}`);
|
||||
console.log(` ID: ${flag.id}`);
|
||||
console.log(` Status: ${flag.status}`);
|
||||
console.log(` Target: ${flag.target}`);
|
||||
console.log(` Description: ${flag.description || "N/A"}`);
|
||||
console.log(` Rollout Strategy: ${flag.rolloutStrategy || "N/A"}`);
|
||||
console.log(` Rollout Config: ${flag.rolloutConfig || "N/A"}`);
|
||||
console.log(` Start Date: ${flag.startDate || "N/A"}`);
|
||||
console.log(` End Date: ${flag.endDate || "N/A"}`);
|
||||
console.log(` Created: ${flag.createdAt}`);
|
||||
console.log(` Updated: ${flag.updatedAt}`);
|
||||
|
||||
// Verificar si hay problemas con los datos
|
||||
if (flag.rolloutConfig) {
|
||||
try {
|
||||
const parsed = JSON.parse(flag.rolloutConfig);
|
||||
console.log(` ✅ Rollout Config parseable:`, parsed);
|
||||
} catch (e: any) {
|
||||
console.log(` ❌ ERROR parseando Rollout Config: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (flag.metadata) {
|
||||
try {
|
||||
const parsed = JSON.parse(flag.metadata);
|
||||
console.log(` ✅ Metadata parseable:`, parsed);
|
||||
} catch (e: any) {
|
||||
console.log(` ❌ ERROR parseando Metadata: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
||||
|
||||
// Test de creación
|
||||
console.log("🧪 Test: Crear flag temporal...");
|
||||
const testFlag = await prisma.featureFlag.create({
|
||||
data: {
|
||||
name: `test_flag_${Date.now()}`,
|
||||
description: "Flag de test temporal",
|
||||
status: "disabled",
|
||||
target: "global",
|
||||
},
|
||||
});
|
||||
console.log(`✅ Flag creado: ${testFlag.name}`);
|
||||
|
||||
// Limpiar
|
||||
await prisma.featureFlag.delete({
|
||||
where: { name: testFlag.name },
|
||||
});
|
||||
console.log(`🗑️ Flag eliminado: ${testFlag.name}\n`);
|
||||
|
||||
console.log("✅ Sistema funcionando correctamente");
|
||||
} catch (error: any) {
|
||||
console.error("❌ ERROR:", error.message);
|
||||
console.error("Stack:", error.stack);
|
||||
console.error("Code:", error.code);
|
||||
console.error("Meta:", error.meta);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
debugFeatureFlags();
|
||||
@@ -11,9 +11,12 @@ export async function loadFeatureFlags(): Promise<void> {
|
||||
logger.info("[FeatureFlags] Inicializando servicio...");
|
||||
await featureFlagService.initialize();
|
||||
logger.info("[FeatureFlags] ✅ Servicio inicializado correctamente");
|
||||
} catch (error) {
|
||||
//@ts-ignore
|
||||
logger.error("[FeatureFlags] ❌ Error al inicializar:", error);
|
||||
} catch (error: any) {
|
||||
logger.error("[FeatureFlags] ❌ Error al inicializar:");
|
||||
logger.error("[FeatureFlags] Message:", error?.message);
|
||||
logger.error("[FeatureFlags] Stack:", error?.stack);
|
||||
logger.error("[FeatureFlags] Code:", error?.code);
|
||||
logger.error("[FeatureFlags] Meta:", error?.meta);
|
||||
// No lanzamos el error para no bloquear el arranque del bot
|
||||
// El servicio funcionará en modo fail-safe (todos los flags disabled)
|
||||
}
|
||||
|
||||
@@ -64,9 +64,12 @@ class FeatureFlagService {
|
||||
logger.info(
|
||||
`[FeatureFlags] Inicializado con ${this.flagsCache.size} flags`
|
||||
);
|
||||
} catch (error) {
|
||||
//@ts-ignore
|
||||
logger.error("[FeatureFlags] Error al inicializar:", error);
|
||||
} catch (error: any) {
|
||||
logger.error("[FeatureFlags] Error al inicializar:", {
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
name: error?.name,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -106,9 +109,13 @@ class FeatureFlagService {
|
||||
logger.debug(
|
||||
`[FeatureFlags] Caché actualizado: ${this.flagsCache.size} flags`
|
||||
);
|
||||
} catch (error) {
|
||||
//@ts-ignore
|
||||
logger.error("[FeatureFlags] Error al refrescar caché:", error);
|
||||
} catch (error: any) {
|
||||
logger.error("[FeatureFlags] Error al refrescar caché:", {
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
code: error?.code,
|
||||
meta: error?.meta,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -555,12 +562,13 @@ class FeatureFlagService {
|
||||
this.flagsCache.set(config.name, config);
|
||||
|
||||
logger.info(`[FeatureFlags] Flag "${config.name}" actualizado`);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[FeatureFlags] Error al setear flag "${config.name}":`,
|
||||
//@ts-ignore
|
||||
error
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.error(`[FeatureFlags] Error al setear flag "${config.name}":`, {
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
code: error?.code,
|
||||
meta: error?.meta,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -578,12 +586,13 @@ class FeatureFlagService {
|
||||
this.stats.delete(flagName);
|
||||
|
||||
logger.info(`[FeatureFlags] Flag "${flagName}" eliminado`);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[FeatureFlags] Error al eliminar flag "${flagName}":`,
|
||||
//@ts-ignore
|
||||
error
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.error(`[FeatureFlags] Error al eliminar flag "${flagName}":`, {
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
code: error?.code,
|
||||
meta: error?.meta,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user