Unificação do arquivo do registro de operações e maior detalhanmento em caso de update.
This commit is contained in:
parent
817d542631
commit
e4c398eef0
@ -30,10 +30,49 @@ namespace Application
|
|||||||
_rateLimiter?.Dispose();
|
_rateLimiter?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum LogType { Info, Error, Operation, UpdateMeasurement }
|
||||||
|
|
||||||
|
private record LogItem(
|
||||||
|
LogType Tipo,
|
||||||
|
string Perfil,
|
||||||
|
string Ponto,
|
||||||
|
double DiaNum,
|
||||||
|
int Minuto,
|
||||||
|
string Status,
|
||||||
|
string Mensagem,
|
||||||
|
int Inseridos,
|
||||||
|
int Atualizados,
|
||||||
|
Medicao? Antes,
|
||||||
|
Medicao? Depois,
|
||||||
|
DateTime Timestamp)
|
||||||
|
{
|
||||||
|
public string ToCsvLine()
|
||||||
|
{
|
||||||
|
static string Esc(string? s) => (s ?? "").Replace(";", ",").Replace("\r", " ").Replace("\n", " ");
|
||||||
|
static string FMed(Medicao? m) =>
|
||||||
|
m is null ? "" : $"{Esc(m.Ponto)}|{m.DiaNum}|{m.Minuto}|{Esc(m.Origem)}|{m.AtivaConsumo?.ToString(CultureInfo.InvariantCulture) ?? ""}|{m.AtivaGeracao?.ToString(CultureInfo.InvariantCulture) ?? ""}|{m.ReativaConsumo?.ToString(CultureInfo.InvariantCulture) ?? ""}|{m.ReativaGeracao?.ToString(CultureInfo.InvariantCulture) ?? ""}";
|
||||||
|
|
||||||
|
return string.Join(";", new[]
|
||||||
|
{
|
||||||
|
Tipo.ToString(),
|
||||||
|
Esc(Perfil),
|
||||||
|
Esc(Ponto),
|
||||||
|
DiaNum.ToString(CultureInfo.InvariantCulture),
|
||||||
|
Minuto.ToString(),
|
||||||
|
Esc(Status),
|
||||||
|
Esc(Mensagem),
|
||||||
|
Inseridos.ToString(),
|
||||||
|
Atualizados.ToString(),
|
||||||
|
FMed(Antes),
|
||||||
|
FMed(Depois),
|
||||||
|
Timestamp.ToString("o")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(DateTime dataIni, DateTime dataFim, string caminhoLog, CancellationToken ct)
|
public async Task ExecuteAsync(DateTime dataIni, DateTime dataFim, string caminhoLog, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var errosPersistentes = new ConcurrentBag<string>();
|
var logs = new ConcurrentBag<LogItem>();
|
||||||
var operacoesLog = new ConcurrentBag<string>();
|
|
||||||
var perfis = (await _accessRepository.ObterPerfisAsync(ct)).ToList();
|
var perfis = (await _accessRepository.ObterPerfisAsync(ct)).ToList();
|
||||||
|
|
||||||
var endpoint = new Uri("https://servicos.ccee.org.br/ws/v2/MedidaCincoMinutosBSv2");
|
var endpoint = new Uri("https://servicos.ccee.org.br/ws/v2/MedidaCincoMinutosBSv2");
|
||||||
@ -41,42 +80,39 @@ namespace Application
|
|||||||
|
|
||||||
await Parallel.ForEachAsync(perfis, async (perfil, ctPerfil) =>
|
await Parallel.ForEachAsync(perfis, async (perfil, ctPerfil) =>
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"{DateTime.Now}: Iniciado ponto {perfil.CodigoSCDE}");
|
|
||||||
if (perfil.Codigo5Minutos == "0" || perfil.Codigo5Minutos == string.Empty || perfil.Codigo5Minutos == null)
|
if (perfil.Codigo5Minutos == "0" || perfil.Codigo5Minutos == string.Empty || perfil.Codigo5Minutos == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Pular {perfil.CodigoSCDE} - (cod 5 min pendente)");
|
Console.WriteLine($"Pular {perfil.CodigoSCDE} - (cod 5 min pendente)");
|
||||||
errosPersistentes.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};{dataIni.ToOADate()};ERRO;cod_5min pendente");
|
logs.Add(new LogItem(LogType.Error, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dataIni.ToOADate(), 0, "ERRO", "cod_5min pendente", 0, 0, null, null, DateTime.UtcNow));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var existentes = await ObterMedicoesComRetry(perfil.CodigoSCDE, dataIni, dataFim, ctPerfil, errosPersistentes);
|
var existentes = await ObterMedicoesComRetry(perfil.CodigoSCDE, dataIni, dataFim, ctPerfil, logs);
|
||||||
|
|
||||||
// Paraleliza os dias deste perfil; o semáforo limita as requisições simultâneas
|
|
||||||
await Parallel.ForEachAsync(datas, ctPerfil, async (dia, ctDia) =>
|
await Parallel.ForEachAsync(datas, ctPerfil, async (dia, ctDia) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ProcessarDiaAsync(perfil, dia, existentes, endpoint, errosPersistentes, operacoesLog, ctDia);
|
await ProcessarDiaAsync(perfil, dia, existentes, endpoint, logs, ctDia);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
operacoesLog.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};{dia.ToOADate()};ERRO;{ex.Message.Replace("\n", "-n-")}");
|
logs.Add(new LogItem(LogType.Error, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dia.ToOADate(), 0, "ERRO", ex.Message.Replace("\n", "-n-"), 0, 0, null, null, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Console.WriteLine($"{DateTime.Now}: Finalizado ponto {perfil.CodigoSCDE}");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cabeçalho do log
|
var linhas = new List<string>
|
||||||
var linhasLog = new List<string> { "Perfil;Ponto;DiaNum;Status;Mensagem;Inseridos;Atualizados" };
|
{
|
||||||
linhasLog.AddRange(operacoesLog);
|
"Tipo;Perfil;Ponto;DiaNum;Minuto;Status;Mensagem;Inseridos;Atualizados;Antes;Depois;Timestamp"
|
||||||
linhasLog.AddRange(errosPersistentes);
|
};
|
||||||
|
linhas.AddRange(logs.Select(l => l.ToCsvLine()));
|
||||||
|
|
||||||
File.WriteAllLines(caminhoLog, linhasLog);
|
File.WriteAllLines(caminhoLog, linhas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IDictionary<(string, double, int), Medicao>> ObterMedicoesComRetry(
|
private async Task<IDictionary<(string, double, int), Medicao>> ObterMedicoesComRetry(
|
||||||
string codigoSCDE, DateTime dataIni, DateTime dataFim, CancellationToken ct, ConcurrentBag<string> errosPersistentes)
|
string codigoSCDE, DateTime dataIni, DateTime dataFim, CancellationToken ct, ConcurrentBag<LogItem> logs)
|
||||||
{
|
{
|
||||||
int tentativas = 0;
|
int tentativas = 0;
|
||||||
while (tentativas < 3)
|
while (tentativas < 3)
|
||||||
@ -90,7 +126,7 @@ namespace Application
|
|||||||
tentativas++;
|
tentativas++;
|
||||||
if (tentativas >= 3)
|
if (tentativas >= 3)
|
||||||
{
|
{
|
||||||
errosPersistentes.Add($";{codigoSCDE};{dataIni.ToOADate()};Erro;{ex.Message.Replace("\n", "-n-")}");
|
logs.Add(new LogItem(LogType.Error, "", codigoSCDE, dataIni.ToOADate(), 0, "Erro", ex.Message.Replace("\n", "-n-"), 0, 0, null, null, DateTime.UtcNow));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
int backoff = (int)Math.Pow(2, tentativas) * 1000;
|
int backoff = (int)Math.Pow(2, tentativas) * 1000;
|
||||||
@ -104,21 +140,18 @@ namespace Application
|
|||||||
private async Task ProcessarDiaAsync(
|
private async Task ProcessarDiaAsync(
|
||||||
Perfil perfil,
|
Perfil perfil,
|
||||||
DateTime dia,
|
DateTime dia,
|
||||||
IDictionary<(string, double, int),
|
IDictionary<(string, double, int), Medicao> existentes,
|
||||||
Medicao> existentes,
|
|
||||||
Uri endpoint,
|
Uri endpoint,
|
||||||
ConcurrentBag<string> errosPersistentes,
|
ConcurrentBag<LogItem> logs,
|
||||||
ConcurrentBag<string> operacoesLog,
|
|
||||||
CancellationToken ct)
|
CancellationToken ct)
|
||||||
{
|
{
|
||||||
if (perfil.DataDeMigracao > dia)
|
if (perfil.DataDeMigracao > dia)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Pular {perfil.CodigoSCDE} - {dia.ToShortDateString()} (antes da migração)");
|
Console.WriteLine($"Pular {perfil.CodigoSCDE} - {dia.ToShortDateString()} (antes da migração)");
|
||||||
errosPersistentes.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};Fora da data de migração {perfil.DataDeMigracao} x {dia}");
|
logs.Add(new LogItem(LogType.Info, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dia.ToOADate(), 0, "Fora da data de migração", $"Data de migração {perfil.DataDeMigracao} x {dia}", 0, 0, null, null, DateTime.UtcNow));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Acumulador de medidas (todas as páginas)
|
// Acumulador de medidas (todas as páginas)
|
||||||
var acumulador = new List<XElement>();
|
var acumulador = new List<XElement>();
|
||||||
int paginaAtual = 1;
|
int paginaAtual = 1;
|
||||||
@ -168,7 +201,7 @@ namespace Application
|
|||||||
if (ex.ErrorCode == "4001" || ex.ErrorCode == "2001")
|
if (ex.ErrorCode == "4001" || ex.ErrorCode == "2001")
|
||||||
{
|
{
|
||||||
// erro persistente, registra e interrompe processamento deste dia/ponto
|
// erro persistente, registra e interrompe processamento deste dia/ponto
|
||||||
errosPersistentes.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};{dia.ToOADate()};SOAP Fault: {ex.ErrorCode};{ex.ErrorMessage.Replace("\n", "-n-")}");
|
logs.Add(new LogItem(LogType.Error, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dia.ToOADate(), 0, "SOAP Fault", $"{ex.ErrorCode};{ex.ErrorMessage.Replace("\n", "-n-")}", 0, 0, null, null, DateTime.UtcNow));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
@ -199,7 +232,7 @@ namespace Application
|
|||||||
tentativas++;
|
tentativas++;
|
||||||
if (tentativas >= 5)
|
if (tentativas >= 5)
|
||||||
{
|
{
|
||||||
errosPersistentes.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};{dia.ToOADate()};Erro;{ex.Message.Replace("\n", "-n-")}");
|
logs.Add(new LogItem(LogType.Error, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dia.ToOADate(), 0, "Erro", ex.Message.Replace("\n", "-n-"), 0, 0, null, null, DateTime.UtcNow));
|
||||||
// aborta o processamento do dia após falhas repetidas na mesma página
|
// aborta o processamento do dia após falhas repetidas na mesma página
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -216,11 +249,11 @@ namespace Application
|
|||||||
// ao final de todas as páginas, processa o XML acumulado
|
// ao final de todas as páginas, processa o XML acumulado
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ProcessarXMLAsync(acumulador, dia, perfil.Codigo5Minutos, perfil.CodigoSCDE, existentes, ct, operacoesLog);
|
await ProcessarXMLAsync(acumulador, dia, perfil.Codigo5Minutos, perfil.CodigoSCDE, existentes, ct, logs);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
errosPersistentes.Add($"{perfil.Codigo5Minutos};{perfil.CodigoSCDE};{dia.ToOADate()};Erro;{ex.Message.Replace("\n", "-n-")}");
|
logs.Add(new LogItem(LogType.Error, perfil.Codigo5Minutos ?? "", perfil.CodigoSCDE ?? "", dia.ToOADate(), 0, "Erro", ex.Message.Replace("\n", "-n-"), 0, 0, null, null, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,9 +264,10 @@ namespace Application
|
|||||||
string ponto,
|
string ponto,
|
||||||
IDictionary<(string, double, int), Medicao> existentes,
|
IDictionary<(string, double, int), Medicao> existentes,
|
||||||
CancellationToken ct,
|
CancellationToken ct,
|
||||||
ConcurrentBag<string>? operacoesLog = null)
|
ConcurrentBag<LogItem>? logs = null)
|
||||||
{
|
{
|
||||||
// Processa as medidas já acumuladas (antes chamadas faziam paginação)
|
logs ??= new ConcurrentBag<LogItem>();
|
||||||
|
|
||||||
XNamespace ns = "http://xmlns.energia.org.br/BO/v2";
|
XNamespace ns = "http://xmlns.energia.org.br/BO/v2";
|
||||||
|
|
||||||
var medidasProcessadas = acumulador
|
var medidasProcessadas = acumulador
|
||||||
@ -305,7 +339,7 @@ namespace Application
|
|||||||
{
|
{
|
||||||
if (faltantes.Count > 3)
|
if (faltantes.Count > 3)
|
||||||
{
|
{
|
||||||
// Se mais de 3 faltantes na hora, n<EFBFBD>o faz estimativa
|
// Se mais de 3 faltantes na hora, não faz estimativa
|
||||||
var estimada = new Medicao(
|
var estimada = new Medicao(
|
||||||
ponto + "P",
|
ponto + "P",
|
||||||
(dia.ToOADate() - dia.ToOADate() % 1),
|
(dia.ToOADate() - dia.ToOADate() % 1),
|
||||||
@ -365,6 +399,20 @@ namespace Application
|
|||||||
Math.Round(existente.ReativaGeracao ?? 0, 10) != Math.Round(m.ReativaGeracao ?? 0, 10))
|
Math.Round(existente.ReativaGeracao ?? 0, 10) != Math.Round(m.ReativaGeracao ?? 0, 10))
|
||||||
{
|
{
|
||||||
alterados.Add(m);
|
alterados.Add(m);
|
||||||
|
// log detalhado por medição alterada
|
||||||
|
logs.Add(new LogItem(
|
||||||
|
LogType.UpdateMeasurement,
|
||||||
|
perfil,
|
||||||
|
m.Ponto,
|
||||||
|
m.DiaNum,
|
||||||
|
m.Minuto,
|
||||||
|
"ALTERADO",
|
||||||
|
"Medição alterada (antes x depois)",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
existente,
|
||||||
|
m,
|
||||||
|
DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,19 +421,19 @@ namespace Application
|
|||||||
{
|
{
|
||||||
await _postgresRepository.InserirMedicoesAsync(novos, ct);
|
await _postgresRepository.InserirMedicoesAsync(novos, ct);
|
||||||
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. {novos.Count:D3} registros inseridos.");
|
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. {novos.Count:D3} registros inseridos.");
|
||||||
operacoesLog?.Add($"{perfil};{ponto};{dia.ToOADate()};OK;Novos;{novos.Count};0");
|
logs.Add(new LogItem(LogType.Operation, perfil, ponto, dia.ToOADate(), 0, "OK", "Novos", novos.Count, 0, null, null, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alterados.Any())
|
if (alterados.Any())
|
||||||
{
|
{
|
||||||
await _postgresRepository.AtualizarMedicoesAsync(alterados, ct);
|
await _postgresRepository.AtualizarMedicoesAsync(alterados, ct);
|
||||||
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. {alterados.Count:D3} registros atualizados.");
|
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. {alterados.Count:D3} registros atualizados.");
|
||||||
operacoesLog?.Add($"{perfil};{ponto};{dia.ToOADate()};OK;Atualizados;0;{alterados.Count}");
|
// logs.Add(new LogItem(LogType.Operation, perfil, ponto, dia.ToOADate(), 0, "OK", "Atualizados", 0, alterados.Count, null, null, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
if (!novos.Any() && !alterados.Any())
|
if (!novos.Any() && !alterados.Any())
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. 000 registros alterados.");
|
Console.WriteLine($"Ponto {ponto}. Dia {dia:dd/MM/yyyy}. 000 registros alterados.");
|
||||||
operacoesLog?.Add($"{perfil};{ponto};{dia.ToOADate()};OK;Sem alterações;0;0");
|
logs.Add(new LogItem(LogType.Info, perfil, ponto, dia.ToOADate(), 0, "OK", "Sem alterações", 0, 0, null, null, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,9 @@ class Program
|
|||||||
string caminhoLog = $@"\\srv-dados\documentos\Back\Carteira x.x\Codigo\Erros\log_erros_{inicio:MM_dd_HH_mm}.csv";
|
string caminhoLog = $@"\\srv-dados\documentos\Back\Carteira x.x\Codigo\Erros\log_erros_{inicio:MM_dd_HH_mm}.csv";
|
||||||
//DateTime dataIni = new DateTime(inicio.Year, inicio.Month, 1);
|
//DateTime dataIni = new DateTime(inicio.Year, inicio.Month, 1);
|
||||||
//DateTime dataFim = new DateTime(inicio.Year, inicio.Month, inicio.Day);
|
//DateTime dataFim = new DateTime(inicio.Year, inicio.Month, inicio.Day);
|
||||||
//junho finalizado
|
//agosto finalizado
|
||||||
DateTime dataIni = new DateTime(inicio.Year, 11, 01);
|
DateTime dataIni = new DateTime(inicio.Year, 09, 01);
|
||||||
DateTime dataFim = new DateTime(inicio.Year, 11, 14);
|
DateTime dataFim = new DateTime(inicio.Year, 10, 01);
|
||||||
|
|
||||||
// Configuração de dependências (pode usar um container DI depois)
|
// Configuração de dependências (pode usar um container DI depois)
|
||||||
var postgresRepo = new PostgresRepository(PG_CONN_STRING_PROD);
|
var postgresRepo = new PostgresRepository(PG_CONN_STRING_PROD);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user