Implementada lógica de actualización segura en PLCViewModel para evitar actualizaciones concurrentes y mejorar la gestión de tiempos de espera.

This commit is contained in:
Miguel 2025-06-29 17:44:31 +02:00
parent 4a05bad08a
commit 4aa1e8ec27
1 changed files with 163 additions and 111 deletions

View File

@ -57,6 +57,13 @@ namespace LibS7Adv
private DateTime _lastUpdateStartTime = DateTime.MinValue; private DateTime _lastUpdateStartTime = DateTime.MinValue;
private TimeSpan _updateTimeout = TimeSpan.FromSeconds(10); // Timeout para reintentar después de un tiempo private TimeSpan _updateTimeout = TimeSpan.FromSeconds(10); // Timeout para reintentar después de un tiempo
// Añadir protección contra loops infinitos
private readonly object _updateLock = new object();
private int _concurrentUpdateCount = 0;
private const int MAX_CONCURRENT_UPDATES = 1;
private DateTime _lastUpdateAttempt = DateTime.MinValue;
private readonly TimeSpan _minUpdateInterval = TimeSpan.FromSeconds(2);
[ObservableProperty] [ObservableProperty]
PlcData plcData = new PlcData(); PlcData plcData = new PlcData();
@ -122,6 +129,14 @@ namespace LibS7Adv
{ {
IsConnected = false; IsConnected = false;
PlcData.ConnectionStatus = "offline"; PlcData.ConnectionStatus = "offline";
// Limpiar estado al desconectar
lock (_updateLock)
{
_isUpdating = false;
_concurrentUpdateCount = 0;
}
Instance = null; Instance = null;
} }
@ -130,10 +145,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Actualizar cuando recibimos el evento // Actualizar cuando recibimos el evento
UpdateTagList(); SafeUpdateTagList();
// Cuando la actualización se completa exitosamente, desactivar la bandera // Cuando la actualización se completa exitosamente, desactivar la bandera
if (IsConfigured) if (IsConfigured)
{ {
@ -141,8 +156,45 @@ namespace LibS7Adv
} }
else else
{ {
// Si no se pudo configurar, programar un reintento después de un tiempo // Si no se pudo configurar, programar UN SOLO reintento después de un tiempo
Task.Delay(1000).ContinueWith(_ => UpdateTagList()); // Solo si no hay otra actualización en curso
lock (_updateLock)
{
if (_concurrentUpdateCount == 0)
{
Task.Delay(2000).ContinueWith(_ => SafeUpdateTagList());
}
}
}
}
private void SafeUpdateTagList()
{
// Verificar si podemos hacer la actualización
lock (_updateLock)
{
// No permitir más de una actualización concurrente
if (_concurrentUpdateCount >= MAX_CONCURRENT_UPDATES)
return;
// No actualizar muy frecuentemente
if (DateTime.Now - _lastUpdateAttempt < _minUpdateInterval)
return;
_concurrentUpdateCount++;
_lastUpdateAttempt = DateTime.Now;
}
try
{
UpdateTagList();
}
finally
{
lock (_updateLock)
{
_concurrentUpdateCount--;
}
} }
} }
@ -150,7 +202,7 @@ namespace LibS7Adv
{ {
IsConfigured = false; IsConfigured = false;
_isUpdating = true; _isUpdating = true;
try try
{ {
Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB | ETagListDetails.M, true); // Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB | ETagListDetails.M, true); //
@ -173,7 +225,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return false; return false;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -182,13 +234,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return false; return false;
} }
if (sTag == null) if (sTag == null)
{ return false; } { return false; }
var tag = ParseTagAddress(sTag); var tag = ParseTagAddress(sTag);
@ -213,10 +265,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = sTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -236,7 +288,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return false; return false;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -245,13 +297,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return false; return false;
} }
if (sTag == null) if (sTag == null)
{ return false; } { return false; }
var tag = ParseTagAddress(sTag); var tag = ParseTagAddress(sTag);
@ -277,10 +329,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = sTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -300,7 +352,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return ""; return "";
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -308,13 +360,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return ""; return "";
} }
if (sTag == null) if (sTag == null)
{ return ""; } { return ""; }
@ -377,10 +429,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = sTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -404,13 +456,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return false; return false;
} }
return Instance?.OutputArea.ReadBit(pByte, (byte)pBit) ?? false; return Instance?.OutputArea.ReadBit(pByte, (byte)pBit) ?? false;
} }
catch (Exception ex) catch (Exception ex)
@ -420,10 +472,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando..."; PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando...";
} }
else else
@ -445,13 +497,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return; return;
} }
Instance?.InputArea.WriteBit(pByte, (byte)pBit, pValue); Instance?.InputArea.WriteBit(pByte, (byte)pBit, pValue);
} }
catch (Exception ex) catch (Exception ex)
@ -461,10 +513,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando..."; PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando...";
} }
else else
@ -473,7 +525,7 @@ namespace LibS7Adv
} }
} }
} }
public void EscribirTag(string pTag, SDataValue Value) public void EscribirTag(string pTag, SDataValue Value)
{ {
try try
@ -483,7 +535,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return; return;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -491,13 +543,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return; return;
} }
Instance?.Write(pTag, Value); Instance?.Write(pTag, Value);
} }
catch (Exception ex) catch (Exception ex)
@ -507,10 +559,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -519,7 +571,7 @@ namespace LibS7Adv
} }
} }
} }
public SDataValue LeerTag(string pTag) public SDataValue LeerTag(string pTag)
{ {
try try
@ -529,7 +581,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return new SDataValue(); return new SDataValue();
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -537,13 +589,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return new SDataValue(); return new SDataValue();
} }
return Instance.Read(pTag); return Instance.Read(pTag);
} }
catch (Exception ex) catch (Exception ex)
@ -553,10 +605,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -566,7 +618,7 @@ namespace LibS7Adv
return new SDataValue(); return new SDataValue();
} }
} }
public void EscribirTagBool(string pTag, bool pValue) public void EscribirTagBool(string pTag, bool pValue)
{ {
try try
@ -576,7 +628,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return; return;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -584,13 +636,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return; return;
} }
Instance?.WriteBool(pTag, pValue); Instance?.WriteBool(pTag, pValue);
} }
catch (Exception ex) catch (Exception ex)
@ -600,10 +652,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -621,7 +673,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return; return;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -629,13 +681,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return; return;
} }
Instance?.WriteInt16(pTag, (short)pValue); Instance?.WriteInt16(pTag, (short)pValue);
} }
catch (Exception ex) catch (Exception ex)
@ -645,10 +697,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -667,7 +719,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return false; return false;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -675,13 +727,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return false; return false;
} }
bool result = Instance?.ReadBool(pTag) ?? false; bool result = Instance?.ReadBool(pTag) ?? false;
return result; return result;
} }
@ -692,10 +744,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -715,7 +767,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return 0; return 0;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -723,13 +775,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return 0; return 0;
} }
int? result = Instance?.ReadInt16(pTag); int? result = Instance?.ReadInt16(pTag);
return result; return result;
} }
@ -740,10 +792,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -763,7 +815,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return 0; return 0;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -771,13 +823,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar leer durante la actualización // No intentar leer durante la actualización
return 0; return 0;
} }
int? result = Instance?.ReadInt32(pTag); int? result = Instance?.ReadInt32(pTag);
return result; return result;
} }
@ -788,10 +840,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else
@ -811,7 +863,7 @@ namespace LibS7Adv
PlcData.LastError = "Not Connected"; PlcData.LastError = "Not Connected";
return; return;
} }
// Verificar si estamos en proceso de actualización // Verificar si estamos en proceso de actualización
if (_isUpdating) if (_isUpdating)
{ {
@ -819,13 +871,13 @@ namespace LibS7Adv
if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) if (DateTime.Now - _lastUpdateStartTime > _updateTimeout)
{ {
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
UpdateTagList(); SafeUpdateTagList();
} }
// No intentar escribir durante la actualización // No intentar escribir durante la actualización
return; return;
} }
Instance?.WriteInt32(pTag, pValue); Instance?.WriteInt32(pTag, pValue);
} }
catch (Exception ex) catch (Exception ex)
@ -835,10 +887,10 @@ namespace LibS7Adv
{ {
_isUpdating = true; _isUpdating = true;
_lastUpdateStartTime = DateTime.Now; _lastUpdateStartTime = DateTime.Now;
// Iniciar actualización de tags // Iniciar actualización de tags de forma segura
Task.Run(() => UpdateTagList()); SafeUpdateTagList();
PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; PlcData.LastError = pTag + ": Tags no actualizados, reintentando...";
} }
else else