fix(historian): respect gateway ceilings and history value contracts
v2-ci / build (pull_request) Successful in 5m10s
v2-ci / unit-tests (pull_request) Failing after 28m34s

This commit is contained in:
Joseph Doherty
2026-10-13 03:51:04 -04:00
parent 66a2b0c3e9
commit 97668d26d3
15 changed files with 474 additions and 29 deletions
@@ -137,6 +137,7 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
catch (Exception ex)
{
RecordFailure(ex);
if (IsTransportFailure(ex)) throw new System.IO.IOException("Historian read transport is unavailable.", ex);
throw;
}
}
@@ -232,6 +233,7 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
catch (Exception ex)
{
RecordFailure(ex);
if (IsTransportFailure(ex)) throw new System.IO.IOException("Historian read transport is unavailable.", ex);
throw;
}
}
@@ -316,6 +318,7 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
catch (Exception ex)
{
RecordFailure(ex);
if (IsTransportFailure(ex)) throw new System.IO.IOException("Historian read transport is unavailable.", ex);
throw;
}
}
@@ -443,6 +446,7 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
catch (Exception ex)
{
RecordFailure(ex);
if (IsTransportFailure(ex)) throw new System.IO.IOException("Historian read transport is unavailable.", ex);
throw;
}
}
@@ -538,6 +542,7 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
catch (Exception ex)
{
RecordFailure(ex);
if (IsTransportFailure(ex)) throw new System.IO.IOException("Historian read transport is unavailable.", ex);
throw;
}
}
@@ -701,6 +706,11 @@ public sealed class QuestDbHistorianDataSource : IHistorianDataSource
private void RecordSuccess() => _health.RecordSuccess();
/// <summary>Classifies provider transport/timeouts, keeping SQL/query errors distinct (#697).</summary>
private static bool IsTransportFailure(Exception ex) => ex is NpgsqlException { IsTransient: true } and not PostgresException
|| ex is PostgresException pg && (pg.SqlState.StartsWith("08", StringComparison.Ordinal)
|| pg.SqlState is "57P01" or "57P02" or "57P03");
private void RecordFailure(Exception ex)
{
// A cancelled read (deadline / client abort) is not a backend fault (the counters ignore it too).