conflicto resuelto
This commit is contained in:
commit
96e80a1948
12
.env
12
.env
@ -1,6 +1,6 @@
|
||||
#Configuración de la base de datos
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5434
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_USER=admin
|
||||
DB_PASSWORD=admin
|
||||
DB_NAME=gotestdb
|
||||
@ -8,7 +8,7 @@ DB_MAX_OPEN_CONNS=25
|
||||
DB_MAX_IDLE_CONNS=10
|
||||
DB_CONN_MAX_LIFETIME=30m
|
||||
#Redis
|
||||
REDIS_HOST=localhost
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=TuPasswordSegura123
|
||||
REDIS_DB=0
|
||||
@ -16,7 +16,7 @@ REDIS_TTL=10m
|
||||
REDIS_SUBSCRIBE=cron:reload
|
||||
#Log
|
||||
LOG_FILE_PATH=logs/syncronizador.log
|
||||
LOG_LEVEL=debug
|
||||
LOG_LEVEL=info
|
||||
LOG_MAX_SIZE=10
|
||||
LOG_MAX_BACKUPS=7
|
||||
LOG_MAX_AGE=30
|
||||
@ -41,13 +41,13 @@ ENCRYPTION_KEY=12345678901234567890123456789012
|
||||
|
||||
|
||||
|
||||
AUTH_ENDPOINT= http://localhost:8085/auth/headers
|
||||
AUTH_ENDPOINT=http://authsvc:8080/auth/headers
|
||||
AUTH_AUTORIZATION='Basic d29ya2VyLXJlbmRpY2lvbjpwcnVlYmE='
|
||||
AUTH_METHOD=POST
|
||||
|
||||
TM_HEADER_ORIGIN=https://azure-function.timemanagerweb.com
|
||||
TM_HEADER_TENANT_NAME=pruebas-dos
|
||||
TM_HEADER_USER_AGENT='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36'
|
||||
TM_HEADER_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
|
||||
|
||||
|
||||
# Configuración de correo SMTP
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/tuusuario/go-sync-service/internal/config"
|
||||
@ -16,25 +17,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configurar zona horaria por defecto del proceso
|
||||
initTimezone()
|
||||
|
||||
// Cargar configuración
|
||||
conf, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
fmt.Println("❌ Error cargando configuración:", err)
|
||||
fmt.Println("Error cargando configuración:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Inicializar logger con configuración
|
||||
config.InitLogger(conf)
|
||||
config.Log.Info("🚀 Iniciando servicio: go-sync-service")
|
||||
config.Log.Info("Iniciando servicio: go-sync-service")
|
||||
|
||||
emailService := email.NewSMTPEmailService(conf)
|
||||
|
||||
// Conexión a Redis
|
||||
redisClient := config.GetRedisClient(conf)
|
||||
if err := redisClient.Ping(context.Background()).Err(); err != nil {
|
||||
config.Log.Fatalf("❌ Redis no disponible: %v", err)
|
||||
config.Log.Fatalf("Redis no disponible: %v", err)
|
||||
}
|
||||
config.Log.Info("✅ Redis conectado")
|
||||
config.Log.Info("Redis conectado")
|
||||
|
||||
// Crear proveedor de configuración desde Redis
|
||||
redisManager := config.NewRedisManager(redisClient)
|
||||
@ -43,14 +47,14 @@ func main() {
|
||||
// Conexión a Base de Datos
|
||||
database := config.GetDatabaseConnection(conf)
|
||||
if database == nil {
|
||||
config.Log.Fatal("❌ No se pudo establecer la conexión con la base de datos.")
|
||||
config.Log.Fatal("No se pudo establecer la conexión con la base de datos.")
|
||||
}
|
||||
config.Log.Info("✅ Conexión a base de datos establecida")
|
||||
config.Log.Info("Conexión a base de datos establecida")
|
||||
|
||||
scheduler.Start(context.Background(), redisClient, redisConfigProvider, database, *emailService)
|
||||
config.Log.Info("✅ Scheduler en ejecución y escuchando recargas")
|
||||
config.Log.Info("Scheduler en ejecución y escuchando recargas")
|
||||
|
||||
//metrics Grafana
|
||||
// Metrics Grafana/Prometheus
|
||||
metrics.Register()
|
||||
startMetricsServer()
|
||||
|
||||
@ -59,13 +63,24 @@ func main() {
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
<-stop
|
||||
|
||||
config.Log.Info("🛑 Señal de apagado recibida, cerrando servicio...")
|
||||
config.Log.Info("Señal de apagado recibida, cerrando servicio...")
|
||||
}
|
||||
|
||||
func initTimezone() {
|
||||
loc, err := time.LoadLocation("America/La_Paz")
|
||||
if err != nil {
|
||||
// Si falla la carga, mantenemos la zona por defecto del entorno
|
||||
// y solo registramos el problema en stdout para no depender del logger aún.
|
||||
fmt.Println("No se pudo cargar la zona horaria America/La_Paz:", err)
|
||||
return
|
||||
}
|
||||
time.Local = loc
|
||||
}
|
||||
|
||||
func startMetricsServer() {
|
||||
go func() {
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
config.Log.Info("📊 Servidor de métricas en :9100/metrics")
|
||||
http.ListenAndServe(":9100", nil)
|
||||
config.Log.Info("Servidor de métricas en :9100/metrics")
|
||||
_ = http.ListenAndServe(":9100", nil)
|
||||
}()
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
services:
|
||||
syncronizador:
|
||||
container_name: rendicion_gasto_syncronizador
|
||||
environment:
|
||||
- TZ=America/La_Paz
|
||||
- LANG=es_BO.UTF-8
|
||||
- LC_ALL=es_BO.UTF-8
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
@ -11,7 +15,12 @@ services:
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- network_emba
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
compress: "true"
|
||||
networks:
|
||||
network_emba:
|
||||
external: true
|
||||
|
||||
@ -17,9 +17,34 @@ import (
|
||||
|
||||
// Log instancia global del logger
|
||||
var Log = logrus.New()
|
||||
type LocalTimeHook struct {
|
||||
loc *time.Location
|
||||
}
|
||||
|
||||
func (h LocalTimeHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (h LocalTimeHook) Fire(e *logrus.Entry) error {
|
||||
if h.loc != nil {
|
||||
e.Time = e.Time.In(h.loc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func InitLogger(cfg *Config) {
|
||||
// =========================
|
||||
// Zona horaria Bolivia
|
||||
// =========================
|
||||
loc, err := time.LoadLocation("America/La_Paz")
|
||||
if err != nil {
|
||||
// Fallback robusto para contenedores sin tzdata
|
||||
loc = time.FixedZone("America/La_Paz", -4*60*60)
|
||||
}
|
||||
|
||||
time.Local = loc
|
||||
|
||||
// Hook para forzar timestamps de Logrus a hora Bolivia
|
||||
Log.AddHook(LocalTimeHook{loc: loc})
|
||||
// Configurar rotación de logs con Lumberjack
|
||||
rotator := &lumberjack.Logger{
|
||||
Filename: cfg.LogFilePath, // Archivo de logs
|
||||
@ -56,7 +81,7 @@ func InitLogger(cfg *Config) {
|
||||
|
||||
//elastic
|
||||
if cfg.ElasticEnabled {
|
||||
Log.Debug("✅ Elasticsearch enabled")
|
||||
Log.Info("✅ Elasticsearch enabled")
|
||||
es, err := elasticsearch.NewClient(elasticsearch.Config{
|
||||
Addresses: []string{cfg.ElasticURL},
|
||||
})
|
||||
|
||||
@ -64,7 +64,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st
|
||||
|
||||
// Procesar lote
|
||||
if len(batch) == batchSize || i == len(*rawData)-1 {
|
||||
config.Log.Debugf(logPrefix+" Procesando batch de %d registros", len(batch))
|
||||
config.Log.Println(logPrefix+" Procesando batch de %d registros", len(batch))
|
||||
|
||||
if len(persistencia.UpdateBy) > 0 {
|
||||
// Updates con múltiples campos
|
||||
@ -81,7 +81,7 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st
|
||||
whereValues = append(whereValues, val)
|
||||
}
|
||||
if len(whereParts) < len(persistencia.UpdateBy) {
|
||||
config.Log.Warnf("⚠️ Registro incompleto para update (faltan claves): %+v", row)
|
||||
config.Log.Debugf("⚠️ Registro incompleto para update (faltan claves): %+v", row)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -108,10 +108,10 @@ func (g *GormDatabase) SyncRows(persistencia dto.Persistencia, rawData *[]map[st
|
||||
config.Log.Errorf("%s ❌ Error en update: %v", logPrefix, res.Error)
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
config.Log.Warnf("%s ⚠️ Ninguna fila afectada con campos: %v valores: %v",
|
||||
/* if res.RowsAffected == 0 {
|
||||
config.Log.Debugf("%s ⚠️ Ninguna fila afectada con campos: %v valores: %v",
|
||||
logPrefix, strings.Join(whereParts, " AND "), printWhereValues(whereValues))
|
||||
}
|
||||
} */
|
||||
}
|
||||
} else {
|
||||
// Inserts con conflicto por PK (UPSERT)
|
||||
@ -173,17 +173,17 @@ func (g *GormDatabase) GetCredencialesFromTemplate(whereTemplate string, variabl
|
||||
query := whereTemplate
|
||||
var args []interface{}
|
||||
|
||||
config.Log.Debugf("🔎 Variables recibidas:")
|
||||
config.Log.Info("🔎 Variables recibidas:")
|
||||
for k, v := range variables {
|
||||
placeholder := "@" + k
|
||||
query = strings.ReplaceAll(query, placeholder, "?")
|
||||
args = append(args, v)
|
||||
config.Log.Debugf(" %s = %v", k, v)
|
||||
config.Log.Infof(" %s = %v", k, v)
|
||||
}
|
||||
|
||||
config.Log.Debugf("📝 Consulta final construida:")
|
||||
config.Log.Debugf(" Query: %s", query)
|
||||
config.Log.Debugf(" Args: %v", args)
|
||||
config.Log.Info("📝 Consulta final construida:")
|
||||
config.Log.Infof(" Query: %s", query)
|
||||
config.Log.Infof(" Args: %v", args)
|
||||
|
||||
err := g.db.Where(query, args...).First(&cred).Error
|
||||
return &cred, err
|
||||
|
||||
@ -155,13 +155,13 @@ func prepareAuthBody(auth dto.ServiceConfig, cred *model.CredencialesSAP, logPre
|
||||
}
|
||||
|
||||
if auth.GQL {
|
||||
config.Log.Debugf("%v 🧠 Preparando auth para GraphQL", logPrefix)
|
||||
config.Log.Infof("%v 🧠 Preparando auth para GraphQL", logPrefix)
|
||||
auth.Rest.Body = map[string]string{
|
||||
"username": cred.UserName,
|
||||
"password": cred.Password,
|
||||
}
|
||||
} else {
|
||||
config.Log.Debugf("%v🧠 Preparando auth para REST", logPrefix)
|
||||
config.Log.Infof("%v🧠 Preparando auth para REST", logPrefix)
|
||||
auth.Rest.Body = map[string]string{
|
||||
"CompanyDB": cred.CompanyDB,
|
||||
"UserName": cred.UserName,
|
||||
|
||||
@ -3,11 +3,12 @@ package fetcher
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tuusuario/go-sync-service/internal/email"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tuusuario/go-sync-service/internal/email"
|
||||
|
||||
"github.com/tuusuario/go-sync-service/internal/config"
|
||||
"github.com/tuusuario/go-sync-service/internal/db"
|
||||
"github.com/tuusuario/go-sync-service/internal/domain/dto"
|
||||
@ -122,6 +123,9 @@ func FetchAllPaginatedManual[T any](host string, service dto.ServiceConfig, logP
|
||||
return nil, fmt.Errorf("%s ❌ error en la petición: %w", logPrefix, err)
|
||||
}
|
||||
|
||||
// DEBUG: imprimir lo que devuelve el servicio
|
||||
config.Log.Debugf("%s Body recibido (REST paginado): %s", logPrefix, string(resp.Body()))
|
||||
|
||||
var result struct {
|
||||
Value []T `json:"value"`
|
||||
}
|
||||
@ -206,6 +210,10 @@ func FetchAllPaginatedManual[T any](host string, service dto.ServiceConfig, logP
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s ❌ error en la petición: %w", logPrefix, err)
|
||||
}
|
||||
|
||||
// DEBUG: imprimir lo que devuelve el servicio sin paginación
|
||||
config.Log.Debugf("%s Body recibido (REST sin paginación): %s", logPrefix, string(resp.Body()))
|
||||
|
||||
var result struct {
|
||||
Value []T `json:"value"`
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ func CargarDesdeRedis[T any](cfg ports.RedisConfigProvider, clave string) (*T, e
|
||||
return nil, fmt.Errorf("error al obtener clave [%s] de redis: %w", clave, err)
|
||||
|
||||
}
|
||||
config.Log.Debugf("🔑 Clave [%s] obtenida de Redis: %s", clave, data)
|
||||
config.Log.Infof("🔑 Clave [%s] obtenida de Redis: %s", clave, data)
|
||||
var result T
|
||||
if err := json.Unmarshal([]byte(data), &result); err != nil {
|
||||
config.Log.Errorf("❌ error al parsear JSON [%s]: %s", clave, err)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user