Orquesta Agentes IA que desarrollan por ti
Verificando...
51-incident-investigation
Procedimiento: Investigaci├│n de Incidentes
Reportes
1 plugin(s)
Editor
Preview
Tareas
0
Info
Titulo
Guía la investigación de incidentes de producción. Define proceso de triaje, recopilación de evidencia, análisis de causa raíz, y comunicación.
Descripcion
Contenido Markdown
17892 caracteres
Guardar
# Procedimiento: Investigaci├│n de Incidentes ## Metadata - **ID**: PROC-51 - **Frecuencia**: Bajo demanda (cuando ocurre un incidente) - **Duraci├│n estimada**: 1-4 horas (seg├║n complejidad) - **Requiere**: Acceso a Sentry, logs, c├│digo fuente, BD (lectura) - **Dependencias**: PROC-02 (Sentry), PROC-03 (BD) - **Bloquea**: Puede bloquear releases si es cr├¡tico ## Objetivo Investigar sistem├íticamente incidentes en producci├│n (errores, race conditions, comportamiento inesperado), identificar root cause, y documentar la soluci├│n. ## Clasificaci├│n de Incidentes | Tipo | Descripci├│n | Ejemplo | Urgencia | |------|-------------|---------|----------| | **Crash** | Excepci├│n no manejada, 500 | `NullReferenceException` en MCP tool | Alta | | **Race Condition** | Comportamiento inconsistente bajo carga | Transaction isolation en `CatalogBaseBuilder` | Alta | | **Data Corruption** | Datos incorrectos en BD | Duplicados, valores null inesperados | Cr├¡tica | | **Performance** | Lentitud, timeouts | Query > 30s, deadlocks | Media | | **Logic Error** | Resultado incorrecto pero sin crash | C├ílculo de precio err├│neo | Media | | **Integration** | Fallo en sistema externo | Icecat API, Amara timeout | Variable | ## Par├ímetros del Incidente Documentar antes de empezar: | Campo | Valor | |-------|-------| | **ID Incidente** | INC-___ | | **Fecha/Hora detecci├│n** | ___ | | **Reportado por** | ___ | | **S├¡ntoma** | ___ | | **Impacto** | ___ usuarios / ___ operaciones | | **Entorno** | Producci├│n / Pre / Dev | | **Sentry Issue ID** | ___ (si aplica) | ## Checklist Ejecutable ### Fase 1: Recolecci├│n de Evidencia (30 min max) #### 1.1 Capturar informaci├│n de Sentry ```bash # Obtener detalles del issue sentry-cli issues show ISSUE-ID --org dmi-hl # Ver eventos recientes del issue sentry-cli issues list-events ISSUE-ID --org dmi-hl ``` Documentar de Sentry: | Campo | Valor | |-------|-------| | Exception Type | | | Message | | | Stacktrace (top 3 frames) | | | Tags relevantes | | | Breadcrumbs (├║ltimos 5) | | | Release/Commit | | | User affected | | | Frequency | ___ eventos en ___ tiempo | - [ ] Informaci├│n de Sentry capturada #### 1.2 Revisar logs del contenedor ```bash # Logs recientes (si hay acceso directo) docker logs bigcapi --since "2h" 2>&1 | grep -i "error\|exception\|fail" # Buscar por correlation ID si existe docker logs bigcapi --since "2h" 2>&1 | grep "REQUEST_ID" # En Portainer: Containers ÔåÆ bigcapi ÔåÆ Logs ``` - [ ] Logs revisados - [ ] Patrones identificados: ___ #### 1.3 Verificar estado de la BD ```sql -- Conexiones activas SELECT DB_NAME(database_id) AS db, COUNT(*) AS connections, SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) AS running FROM sys.dm_exec_sessions WHERE database_id > 0 GROUP BY database_id; -- Queries bloqueadas (si hay deadlock/race condition) SELECT blocking.session_id AS blocking_session, blocked.session_id AS blocked_session, blocked.wait_type, blocked.wait_time / 1000 AS wait_seconds, DB_NAME(blocked.database_id) AS db FROM sys.dm_exec_requests blocked INNER JOIN sys.dm_exec_requests blocking ON blocked.blocking_session_id = blocking.session_id WHERE blocked.blocking_session_id <> 0; -- Transacciones abiertas largas SELECT st.session_id, st.transaction_id, at.name AS transaction_name, at.transaction_begin_time, DATEDIFF(MINUTE, at.transaction_begin_time, GETDATE()) AS minutes_open FROM sys.dm_tran_session_transactions st JOIN sys.dm_tran_active_transactions at ON st.transaction_id = at.transaction_id WHERE DATEDIFF(MINUTE, at.transaction_begin_time, GETDATE()) > 5; ``` - [ ] Estado de BD verificado - [ ] Bloqueos activos: S├¡ / No - [ ] Transacciones largas: S├¡ / No #### 1.4 Identificar cambios recientes ```bash # Commits desde ├║ltimo deploy estable git log --oneline $(git describe --tags --abbrev=0 @^)..HEAD # Archivos modificados git diff --name-only $(git describe --tags --abbrev=0 @^)..HEAD # Buscar cambios en ├írea sospechosa git log --oneline -10 -- src/src/BigCommerceApi/Mcp/Tools/ git log --oneline -10 -- src/src/SupplierCatalog.Sync/ ``` - [ ] Commits recientes revisados - [ ] Commit sospechoso: ___ (si aplica) ### Fase 2: An├ílisis de Root Cause (1-2h) #### 2.1 Localizar el c├│digo problem├ítico ```bash # Buscar por mensaje de error grep -r "mensaje del error" src/ # Buscar por clase/m├®todo del stacktrace grep -rn "NombreClase" src/src/BigCommerceApi/ # Buscar patrones peligrosos comunes grep -rn "\.Result" src/ # Sync over async grep -rn "Task\.Run" src/ # Thread pool abuse grep -rn "lock\s*(" src/ # Locks manuales grep -rn "static.*=" src/ # Estado est├ítico mutable ``` - [ ] C├│digo localizado - [ ] Archivo: ___ - [ ] L├¡nea: ___ #### 2.2 An├ílisis seg├║n tipo de incidente ##### Para Race Conditions / Concurrencia ```csharp // Patrones problem├íticos a buscar: // 1. Check-then-act sin lock if (!_cache.ContainsKey(key)) // ÔåÉ Race condition window { _cache[key] = ComputeValue(); // ÔåÉ Otro thread puede haber a├▒adido } // 2. Shared mutable state private static List _items = new(); // ÔåÉ Peligroso sin lock // 3. Transaction isolation insuficiente using var transaction = connection.BeginTransaction(); // Sin especificar isolation level ÔåÆ default puede no ser suficiente // 4. Lazy initialization sin thread-safety private MyService? _service; public MyService Service => _service ??= new MyService(); // ÔåÉ Race ``` **Checklist Race Condition:** - [ ] ┬┐Hay estado compartido mutable? - [ ] ┬┐Hay check-then-act sin sincronizaci├│n? - [ ] ┬┐El isolation level de transacci├│n es correcto? - [ ] ┬┐Se usa `ConcurrentDictionary` donde corresponde? - [ ] ┬┐Los singletons son thread-safe? ##### Para Errores de Datos / NullReference ```sql -- Buscar datos inconsistentes SELECT * FROM dbo.TablaProblematica WHERE CampoQueDeberiaExistir IS NULL OR CampoNumerico < 0 OR LEN(CampoTexto) = 0; -- Verificar integridad referencial SELECT child.* FROM dbo.TablaHija child LEFT JOIN dbo.TablaPadre parent ON child.ParentId = parent.Id WHERE parent.Id IS NULL; -- Buscar duplicados SELECT CampoUnico, COUNT(*) AS duplicates FROM dbo.Tabla GROUP BY CampoUnico HAVING COUNT(*) > 1; ``` **Checklist Data Error:** - [ ] ┬┐Hay datos null inesperados? - [ ] ┬┐Hay violaciones de integridad? - [ ] ┬┐El problema es en datos existentes o nuevos? - [ ] ┬┐Cu├índo se corrompieron los datos? ##### Para Performance / Timeouts ```sql -- Query m├ís lenta en el ├írea problem├ítica SELECT TOP 5 qs.total_elapsed_time / qs.execution_count / 1000 AS avg_ms, qs.execution_count, SUBSTRING(qt.text, 1, 200) AS query_preview FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt WHERE qt.text LIKE '%TablaProblematica%' ORDER BY avg_ms DESC; ``` **Checklist Performance:** - [ ] ┬┐Hay Table Scans en tablas grandes? - [ ] ┬┐Hay N+1 queries? - [ ] ┬┐Hay locks/deadlocks? - [ ] ┬┐El timeout es en BD o en servicio externo? #### 2.3 Reproducir el problema (si es posible) ```bash # En entorno de desarrollo/test # 1. Crear test que reproduzca el escenario dotnet test --filter "FullyQualifiedName~ReproduceIssue" # 2. Para race conditions, simular concurrencia # A├▒adir test con Parallel.ForEach o Task.WhenAll ``` ```csharp // Test de reproducci├│n para race condition [Fact] public async Task ReproduceRaceCondition() { // Arrange var tasks = Enumerable.Range(0, 10) .Select(_ => _sut.MethodWithRaceCondition()) .ToList(); // Act var results = await Task.WhenAll(tasks); // Assert - si hay race condition, esto puede fallar intermitentemente results.Should().AllBeEquivalentTo(expectedValue); } ``` - [ ] Problema reproducido: S├¡ / No / Intermitente - [ ] Test de reproducci├│n creado: ___ #### 2.4 Determinar Root Cause Completar an├ílisis de 5 Whys: | # | Why | Answer | |---|-----|--------| | 1 | ┬┐Por qu├® ocurri├│ el error? | | | 2 | ┬┐Por qu├® [respuesta anterior]? | | | 3 | ┬┐Por qu├® [respuesta anterior]? | | | 4 | ┬┐Por qu├® [respuesta anterior]? | | | 5 | ┬┐Por qu├® [respuesta anterior]? | | **Root Cause identificado:** ``` [Descripci├│n clara del root cause] ``` - [ ] Root cause identificado ### Fase 3: Soluci├│n (1-2h) #### 3.1 Dise├▒ar el fix | Aspecto | Decisi├│n | |---------|----------| | **Tipo de fix** | C├│digo / Config / Datos / Rollback | | **Archivos a modificar** | | | **Riesgo del fix** | Bajo / Medio / Alto | | **Requiere downtime** | S├¡ / No | | **Requiere migraci├│n de datos** | S├¡ / No | #### 3.2 Implementar fix ```bash git checkout -b fix/incident-INC-XXX # Implementar cambios... # Commit con referencia al incidente git commit -m "fix: [descripci├│n corta] Root cause: [explicaci├│n breve] Fix: [qu├® se cambi├│ y por qu├®] Incident: INC-XXX Sentry: ISSUE-ID PROC-51" ``` ##### Fixes comunes por tipo **Race Condition - Lock:** ```csharp // Antes (race condition) if (!_cache.ContainsKey(key)) _cache[key] = ComputeValue(); // Despu├®s (thread-safe) private static readonly object _lock = new(); lock (_lock) { if (!_cache.ContainsKey(key)) _cache[key] = ComputeValue(); } // O mejor, usar ConcurrentDictionary private static readonly ConcurrentDictionary _cache = new(); _cache.GetOrAdd(key, _ => ComputeValue()); ``` **Race Condition - Transaction Isolation:** ```csharp // Antes (isolation insuficiente) using var transaction = connection.BeginTransaction(); // Despu├®s (isolation expl├¡cito) using var transaction = connection.BeginTransaction(IsolationLevel.Serializable); // O using var transaction = connection.BeginTransaction(IsolationLevel.RepeatableRead); ``` **NullReference - Defensive:** ```csharp // Antes var name = customer.Address.City.Name; // Despu├®s (null-safe) var name = customer?.Address?.City?.Name ?? "Unknown"; // O con validaci├│n expl├¡cita if (customer?.Address?.City is null) { _logger.LogWarning("Customer {Id} has incomplete address", customer?.Id); throw new McpToolException(400, "Direcci├│n incompleta"); } ``` - [ ] Fix implementado - [ ] C├│digo revisado por otro desarrollador (si es cr├¡tico) #### 3.3 A├▒adir tests para prevenir regresi├│n ```csharp [Fact] public async Task MethodName_WhenConcurrentAccess_ShouldNotRaceCondition() { // Test que habr├¡a fallado antes del fix // y pasa despu├®s del fix } [Fact] public async Task MethodName_WhenDataMissing_ShouldHandleGracefully() { // Test del caso edge que caus├│ el problema } ``` - [ ] Test de regresi├│n a├▒adido - [ ] Test pasa con el fix - [ ] Test falla sin el fix (verificar que realmente cubre el caso) #### 3.4 Ejecutar tests completos ```bash cd src dotnet test # Si hay tests de integraci├│n dotnet test --filter "Category=Integration" ``` - [ ] Todos los tests pasan ### Fase 4: Deploy y Verificaci├│n #### 4.1 Deploy a Pre-producci├│n ```bash # Merge a develop (o branch de pre) git checkout develop git merge fix/incident-INC-XXX git push origin develop # O tag para pre git tag -f pre git push origin pre --force ``` - [ ] Deployed a pre - [ ] Smoke test en pre: ___ #### 4.2 Verificar fix en Pre ```bash # Verificar que el error ya no ocurre curl -X POST https://bigcapi-pre.dmi.es/mcp \ -H "Content-Type: application/json" \ -H "X-Api-Key: $PRE_API_KEY" \ -d '{ ... request que causaba el error ... }' # Verificar en Sentry que no hay nuevos eventos sentry-cli issues list --org dmi-hl --project bigcommerce-api \ --query "is:unresolved firstSeen:-1h" ``` - [ ] Error no se reproduce en pre - [ ] No hay errores nuevos en Sentry #### 4.3 Deploy a Producci├│n ```bash git tag -f prod git push origin prod --force ``` - [ ] Deployed a producci├│n - [ ] Smoke test en producci├│n: ___ #### 4.4 Monitorear post-deploy ```bash # Verificar en Sentry durante 1-2 horas sentry-cli issues list --org dmi-hl --project bigcommerce-api \ --query "is:unresolved firstSeen:-2h" # Verificar m├®tricas (si hay dashboard) ``` - [ ] 1h sin recurrencia del error - [ ] 2h sin recurrencia del error - [ ] Issue marcado como resuelto en Sentry ### Fase 5: Documentaci├│n Post-Incidente #### 5.1 Crear documento de incidente Crear archivo `docs/incidents/INC-XXX.md`: ```markdown # Incidente INC-XXX: [T├¡tulo descriptivo] ## Resumen - **Fecha**: YYYY-MM-DD HH:MM - **Duraci├│n**: X horas - **Impacto**: X usuarios afectados, Y operaciones fallidas - **Severidad**: Critical / High / Medium - **Root Cause**: [Una l├¡nea] ## Timeline | Hora | Evento | |------|--------| | HH:MM | Primer reporte del error | | HH:MM | Investigaci├│n iniciada | | HH:MM | Root cause identificado | | HH:MM | Fix deployado a pre | | HH:MM | Fix deployado a prod | | HH:MM | Incidente cerrado | ## Root Cause [Explicaci├│n detallada del problema] ## Soluci├│n [Qu├® se hizo para resolver] ## Lecciones Aprendidas 1. [Qu├® podr├¡amos haber hecho diferente] 2. [Qu├® proceso falt├│] 3. [Qu├® herramienta nos habr├¡a ayudado] ## Acciones Preventivas - [ ] [Acci├│n 1] - Responsable - Fecha - [ ] [Acci├│n 2] - Responsable - Fecha ## Referencias - Sentry: [link] - PR: [link] - Commit: [hash] ``` - [ ] Documento de incidente creado - [ ] Revisado por equipo #### 5.2 Cerrar issue en Sentry ```bash # A├▒adir comentario con resoluci├│n curl -X POST "https://sentry.io/api/0/issues/${ISSUE_ID}/comments/" \ -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Resuelto en commit XXX.\n\nRoot cause: [descripci├│n]\nFix: [descripci├│n]\n\nIncident doc: docs/incidents/INC-XXX.md\n\nPROC-51" }' # Asignar y resolver sentry-cli issues assign $ISSUE_ID --org dmi-hl --user ramac21@gmail.com sentry-cli issues resolve $ISSUE_ID --org dmi-hl ``` - [ ] Issue comentado - [ ] Issue asignado - [ ] Issue resuelto ## Troubleshooting del Procedimiento | S├¡ntoma | Causa | Acci├│n | |---------|-------|--------| | No puedo reproducir | Condici├│n de carrera timing-dependent | A├▒adir sleeps artificiales, aumentar concurrencia | | Error solo en producci├│n | Diferencia de datos/config | Comparar configs, verificar datos de prod | | Fix no resuelve | Root cause incorrecto | Volver a Fase 2, profundizar an├ílisis | | Error vuelve tras fix | Fix incompleto | Buscar otros code paths con mismo problema | | No encuentro el c├│digo | Stacktrace de librer├¡a | Buscar d├│nde se llama la librer├¡a | ## Escalaci├│n | Condici├│n | Escalar a | Medio | |-----------|-----------|-------| | > 2h sin root cause | Lead t├®cnico | Mensaje directo | | Impacto > 100 usuarios/hora | Product Owner | Llamada | | Posible brecha de seguridad | Seguridad | Inmediato | | Requiere rollback de release | DevOps | Llamada | | Problema en sistema externo (Icecat, Amara) | Contacto del proveedor | Email + Ticket | ## Resultado - **├ëxito**: - Root cause identificado - Fix deployado y verificado - No recurrencia en 24h - Documento de incidente creado - **Parcial**: - Workaround aplicado - Fix permanente pendiente con ticket - **Fallo**: - Root cause no identificado ÔåÆ Escalar - Fix causa regresi├│n ÔåÆ Rollback inmediato ## Advertencias - **NO** deployar fix a producci├│n sin verificar en pre - **NO** cerrar incidente sin documentar - **NO** ignorar incidentes intermitentes (pueden ser race conditions) - **SIEMPRE** a├▒adir test de regresi├│n - **SIEMPRE** monitorear post-deploy ## Mensaje de Finalizaci├│n **IMPORTANTE - ACCI├ôN REQUERIDA AL FINALIZAR:** Cuando hayas completado todos los pasos de este procedimiento, DEBES ejecutar el siguiente comando usando la herramienta Bash: Ejecuta: `echo "====== PROCESO TERMINADO [$(date +%H%M%S)] ======" && echo "RESULTADO: Incidente INC-XXX resuelto, root cause identificado, fix deployado"` Sustituye INC-XXX por el ID real del incidente. --- ## Output Estructurado (Nexus) Al finalizar, el agente DEBE generar un bloque JSON con el siguiente formato para que Nexus pueda procesarlo automaticamente: ```json { "result": "success", "summary": "Ejecucion de PROC-51 completada. [Descripcion breve de resultados]", "metrics": { "issues_found": 0, "issues_resolved": 0, "incident_duration_min": 45, "services_affected": 2, "custom": { "procedure_specific_metric": "value" } }, "backlog_items": [ { "title": "Titulo del item de seguimiento", "description": "Descripcion detallada si se requiere accion futura", "priority": "medium", "type": "improvement", "tags": ["proc-51"] } ], "next_steps": [ "Accion recomendada 1", "Accion recomendada 2" ], "warnings": [ "Advertencias encontradas durante la ejecucion" ] } ``` **Campos requeridos:** - `result`: `"success"` | `"partial"` | `"failed"` - `summary`: Resumen ejecutivo en 1-3 lineas **Metricas especificas de este procedure:** - incident_duration_min, root_cause_identified, services_affected **Criterios de resultado:** - `success`: Procedimiento completado sin errores criticos - `partial`: Completado con algunos problemas menores o items pendientes - `failed`: Error critico o no se pudo completar ## Historial de Ejecuciones | Fecha | ID Incidente | Tipo | Root Cause | Fix | Tiempo Total | Doc | |-------|--------------|------|------------|-----|--------------|-----| | | | | | | | |
H1
H2
H3
Bold
Italic
Code
Lista
Num
Task
Code Block
Link
Nexus Platform
Reconectando
Recuperando la conexion
Se ha interrumpido la conexion con el servidor. Estamos reconectando automaticamente.
Reconectando...
Manten esta pestana abierta, volvemos enseguida.
No hemos podido reconectar
El servidor puede estar reiniciandose o tu conexion a internet es inestable.
Reintentar
La sesion ha expirado
Recarga la pagina para iniciar una nueva sesion.
Recargar
Si no vuelve en 30 segundos, recarga la pagina.