Version: 1.0
Fecha: 23 de Mayo, 2026
Estado: INFORMATIVO - Registro de incidentes y resoluciones
Arquitecto: Carlos Alberto Torres Camargo
Documentar los incidentes detectados durante la integracion del upgrade stack-2026-05-23 y su resolucion definitiva. Cada incidente incluye:
Audiencia: Equipo de plataforma. Util como referencia ante sintomas similares en deploys futuros.
BeanDefinitionOverrideException en simappe-client al arrancarSimappeClient no completaba el bootstrap. Logs mostraban:
BeanDefinitionOverrideException: Invalid bean definition with name 'producerFactory'
defined in class path resource [SimappeClient/KafkaConfiguration.class]:
Cannot register bean definition since there is already [bean defined in
SimappeCommons/KafkaConfig.class]
Solo se manifestaba cuando el config-server no entregaba spring.main.allow-bean-definition-overriding=true a tiempo (race condition en el arranque del stack).
Colision de nombres de bean:
SimappeCommons.KafkaConfig.producerFactory() -> ProducerFactory<String, Object>SimappeClient.KafkaConfiguration.producerFactory() -> ProducerFactory<String, Serializable>Spring detectaba el mismo nombre con tipos diferentes. Cuando el config-server no estaba healthy al boot, el override no se permitia y la app crasheaba.
simappe-client en produccion del cliente entre 2026-04-29 y 2026-05-03 (5 dias).spring.main.allow-bean-definition-overriding=true via config-server.Renombrar el bean en SimappeClient (Commons no se toca, regla de licenciante):
// SimappeClient/KafkaConfiguration.java:101
ProducerFactory<String, Serializable> clientProducerFactory() { ... }
// Lineas 114 y 189: actualizar referencias
return new KafkaTemplate<>(clientProducerFactory());
Commit: SimappeClient fix(kafka): rename producerFactory -> clientProducerFactory. Version bump 2.3.2 -> 2.3.3.
docker logs --since 5m simappe-client 2>&1 | grep -E "BeanDefinitionOverrideException"
# Vacio = fix aplicado correctamente
@Bean producerFactory() o equivalentes que colisionen con SimappeCommons.KafkaConfig.host: mongo con UnknownHostExceptionSimappeOauth2Server (v1.4.8 recien deployado) fallo al arrancar:
com.mongodb.MongoTimeoutException: Timed out while waiting for a server
Caused by: com.mongodb.MongoSocketException: mongo
Caused by: java.net.UnknownHostException: mongo
La version vieja del oauth2 (v1.4.6) llevaba 3 semanas healthy con la misma configuracion segun el config-server.
El config-server nuevo (recien deployado tambien) estaba leyendo de una URI Git distinta a la del cliente. Sirviendo configs desde el GitHub del licenciante (https://github.com/<owner>/SimappeConfig.git) en lugar del GitLab Centrica (https://gitlab.centricasoluciones.com/simappe/config/simappeconfig.git).
El GitHub del licenciante tiene spring.data.mongodb.host: mongo (su nombre interno). El cliente usa mongodb-dev como container Mongo.
El application-dev.yml del simappeconfigserver en el workspace Centrica branch release/2026-05-23 tenia hardcoded la URI a GitHub + el PAT del licenciante:
uri: https://github.com/<owner>/SimappeConfig.git
username: ${CONFIG_GIT_USERNAME:<usuario>}
password: ${CONFIG_GIT_PASSWORD:<PAT-token>}
El archivo viajo del workspace del licenciante al cliente como parte del release branch, arrastrando los defaults del licenciante.
Parametrizar los 3 valores con default vacio en los 5 perfiles del config-server (application-{dev,local,localhost,prod,qa}.yml):
uri: ${CONFIG_GIT_URI:}
username: ${CONFIG_GIT_USERNAME:}
password: ${CONFIG_GIT_PASSWORD:}
Commit: simappeconfigserver fix(security): remove hardcoded Git URI/credentials defaults.
Compose del cliente recibe los valores reales via .env:
CONFIG_GIT_URI=https://gitlab.centricasoluciones.com/simappe/config/simappeconfig.git
CONFIG_GIT_USERNAME=<usuario del cliente>
CONFIG_GIT_PASSWORD=<PAT del cliente>
docker exec simappe-config-server printenv | grep -E "CONFIG_GIT"
# Debe mostrar las 3 variables con valores no vacios
curl -s http://localhost:8890/simappe-admin/dev | python3 -c "
import sys, json
d = json.load(sys.stdin)
for src in d.get('propertySources', []):
print(src.get('name'))
" | head -5
# Las URIs deben empezar con https://gitlab.centricasoluciones.com (no GitHub)
UnknownHostException para hosts internos del licenciante (mongo, redis, etc.).curl http://localhost:8890/<servicio>/<profile> muestra propertySources apuntando a un dominio distinto al esperado (github.com en lugar de gitlab.centricasoluciones.com).application-<profile>.yml del simappeconfigserver en el JAR (no debe tener defaults hardcoded de URI/credenciales).application-common.ymlDespues de mergear el feature de simappeconfig con las propiedades nuevas (db-encryption-key, multitenant.*.enabled, etc.) y reiniciar el config-server, los servicios consumidores no recibian las nuevas propiedades.
curl http://localhost:8890/simappe-admin/dev | grep db-encryption
# vacio
Spring Cloud Config Server carga archivos cuyo perfil coincide con SPRING_PROFILES_ACTIVE. El cliente arrancaba los servicios con APP_PROFILE=dev solamente, pero el archivo se llama application-common.yml -> requiere que common este en los perfiles activos.
Hipotesis inicial incorrecta: "application-common.yml es estandar y se carga automaticamente" (mal). Investigacion confirmo que Spring no tiene tal convencion; solo carga archivos cuyo sufijo coincide con un profile activo.
Cambiar el .env de cada grupo de compose:
# Antes
APP_PROFILE=dev
# Despues
APP_PROFILE=dev
SPRING_PROFILES_ACTIVE=common,dev
Recreate de los servicios para que tomen los nuevos perfiles. Verificacion: docker logs <servicio> 2>&1 | grep "profiles are active" debe mostrar "common", "dev".
curl -s http://localhost:8890/simappe-admin/dev | python3 -c "
import sys, json
d = json.load(sys.stdin)
for src in d.get('propertySources', []):
name = src.get('name', '').split('/')[-1]
if 'common' in name:
print('OK:', name)
"
# Debe mostrar: OK: application-common.yml
application-common.yml no aparecen al hacer curl al config-server.common.mongo host no encontrado en Nebula (related a Incidente 2)Tras resolver Incidente 2, los logs de nebula-masters y nebula-accounting-core seguian mostrando un WARN al arrancar:
WARN o.h.e.j.e.i.JdbcEnvironmentInitiator - HHH000339: Could not obtain connection metadata:
PSQLException: ERROR: relation "dual" does not exist
PSQLException: ERROR: current transaction is aborted
nebula-accounting-core/MultiTenantJpaConfig.java:286 tiene hardcoded:
properties.put("hibernate.dialect", "org.hibernate.dialect.OracleDialect");
Este servicio opera con dos motores: Oracle (negocio del cliente) y Postgres (template Simappe). Forzar OracleDialect globalmente aplica el dialect Oracle tambien sobre la connection Postgres. Hibernate intenta ejecutar SELECT * FROM dual (sintaxis Oracle) contra Postgres durante la inicializacion de metadata, lo cual falla.
Confirma el WARN HHH90000025 que Hibernate emite en paralelo:
OracleDialect does not need to be specified explicitly using 'hibernate.dialect'
(remove the property setting and it will be selected by default)
Hibernate 6.6+ autodetecta dialect por connection. Si no se especifica hibernate.dialect, autodetecta OracleDialect para connections Oracle y PostgreSQLDialect para connections Postgres correctamente.
No fix aplicado en stack-2026-05-23. El warning no afecta operacion runtime (es solo metadata initialization, parcial pero funcional). Las queries de negocio contra Oracle siguen funcionando con OracleDialect (correcto). Las queries cross-tenant del template Postgres pueden tener anomalias teoricas pero no se manifiestan en uso normal.
Remover la linea hardcoded en nebula-accounting-core/MultiTenantJpaConfig.java:286. Hibernate autodetectara el dialect por connection.
Verificar despues que el commit fix: set OracleDialect explicitly for Hibernate sequence SQL generation (que originalmente introdujo el hardcode) siga siendo relevante con Hibernate 6.6+. Si no aplica, fixed; si todavia aplica, considerar configurar dialect per-connection en lugar de globalmente.
docker logs nebula-accounting-core 2>&1 | grep -E "HHH000339|HHH90000025"
# Vacio = fix aplicado
connection metadata.relation "dual" does not exist o similares (sintaxis Oracle ejecutada en Postgres).docker compose --force-recreateDespues de docker push con la imagen nueva, ejecutar docker compose up -d --force-recreate <servicio> en nodo-01 levantaba la imagen vieja (anterior a la del push). El container indicaba la version anterior en el banner.
docker compose up -d --force-recreate recrea el container pero no hace pull de la imagen. Si Docker tiene una imagen <servicio>:latest cacheada localmente, la usa sin contactar el registry.
Agregar docker compose pull <servicio> antes del up:
docker compose pull simappe-gateway-server
docker compose up -d --force-recreate simappe-gateway-server
docker inspect <container> --format "{{.Image}}" muestra un sha distinto al del registry actual.En todo procedimiento de deploy, siempre docker compose pull antes del up. Documentado en Estrategias Operativas.
200.118.43.29:2202 no enrutable desde fueraLos scripts deploy-centrica-dev.sh que el licenciante usa para deployar a nodo-01 ejecutaban el push de la imagen al registry interno OK, pero el SSH a 200.118.43.29:2202 (IP externa de nebula.centricasoluciones.com) fallaba con Connection timed out.
La IP 200.118.43.29 requiere VPN al cliente para ser enrutable. El alias SSH nodo-01 (configurado en ~/.ssh/config) usa el hostname nebula.centricasoluciones.com que tambien requiere VPN, pero el cliente tenia VPN activa intermitentemente.
Usar el alias nodo-01 en lugar de la IP hardcoded en los scripts:
# En lugar del bloque del deploy-centrica-dev.sh:
ssh -p 2202 sysadmin@200.118.43.29 'docker compose ...'
# Usar:
ssh nodo-01 'cd ~/docker/compose/<grupo> && docker compose pull <servicio> && docker compose up -d --force-recreate <servicio>'
El alias nodo-01 resuelve via ~/.ssh/config del lado del licenciante (que apunta a nebula.centricasoluciones.com).
Actualizar los deploy-centrica-dev.sh originales del licenciante para usar el alias en lugar de la IP. Esto se hizo en el proceso de deploy de stack-2026-05-23 pero no se commitio al repo (queda como TODO para la proxima release oficial).
nodo-01) este configurado y resuelva al hostname correcto.| # | Incidente | Severidad | Estado | Fix permanente |
|---|---|---|---|---|
| 1 | BeanDefinitionOverrideException Kafka producerFactory | alta | RESUELTO | si (SimappeClient 2.3.3) |
| 2 | Config-server lee de GitHub del licenciante | critica | RESUELTO | parcial (hot fix en workspace cliente, falta formalizar en licenciante) |
| 3 | application-common.yml no cargaba | alta | RESUELTO | si (SPRING_PROFILES_ACTIVE=common,dev) |
| 4 | HHH000339 PSQL "dual" en Nebula | baja | PENDIENTE | no urgente (sin impacto runtime) |
| 5 | Imagen Docker vieja en --force-recreate | media | RESUELTO | si (convencion docker compose pull antes) |
| 6 | IP externa no enrutable | media | RESUELTO | parcial (usar alias SSH, falta actualizar scripts) |
| Documento | Relacion |
|---|---|
| Pendientes Post-Upgrade | Items derivados de incidentes que quedan abiertos |
| Estrategias Operativas | Convenciones derivadas de los incidentes |
| Breaking Changes | Cambios de API que originaron varios incidentes |
| Version | Fecha | Autor | Descripcion |
|---|---|---|---|
| 1.0.0 | 2026-05-24 | Carlos Torres | Registro de incidentes resueltos durante stack-2026-05-23 |