Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/ErrorClassifier.cs
T
Joseph Doherty 7b0b9c7365 refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj,
namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated.
ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated.
SQL roles/logins, LDAP domains, CLI command name, and CLI config dir
(~/.scadalink → ~/.scadabridge) also renamed.

Build green; 5 Host.Tests fail awaiting SQL login rename in next commit.
Pre-existing StaleTagMonitor timing flakes unchanged.

Rename script committed at tools/rename-to-scadabridge.sh.
2026-05-28 09:37:45 -04:00

79 lines
3.3 KiB
C#

using System.Net;
namespace ZB.MOM.WW.ScadaBridge.ExternalSystemGateway;
/// <summary>
/// WP-8: Classifies HTTP errors as transient or permanent.
/// Transient: connection refused, timeout, HTTP 408/429/5xx.
/// Permanent: HTTP 4xx (except 408/429).
/// </summary>
public static class ErrorClassifier
{
/// <summary>
/// Determines whether an HTTP status code represents a transient failure.
/// Transient: HTTP 5xx, 408 (Request Timeout) and 429 (Too Many Requests).
/// Every other non-success status (the remaining 4xx) defaults to permanent —
/// a permanent failure is the safe default because retrying a 4xx is unlikely to
/// succeed and risks duplicate side effects.
/// </summary>
/// <param name="statusCode">The HTTP status code to classify.</param>
public static bool IsTransient(HttpStatusCode statusCode)
{
var code = (int)statusCode;
return code >= 500 || code == 408 || code == 429;
}
/// <summary>
/// Determines whether an exception represents a transient failure.
/// </summary>
/// <param name="exception">The exception to classify.</param>
public static bool IsTransient(Exception exception)
{
return exception is HttpRequestException
or TaskCanceledException
or TimeoutException
or OperationCanceledException;
}
/// <summary>
/// Creates a TransientException for S&amp;F buffering.
/// </summary>
/// <param name="message">Human-readable failure description.</param>
/// <param name="inner">Optional inner exception that caused the transient failure.</param>
public static TransientExternalSystemException AsTransient(string message, Exception? inner = null)
{
return new TransientExternalSystemException(message, inner);
}
}
/// <summary>
/// Exception type that signals a transient failure suitable for store-and-forward retry.
/// </summary>
public class TransientExternalSystemException : Exception
{
/// <summary>Initializes a new <see cref="TransientExternalSystemException"/> with a message and optional inner exception.</summary>
/// <param name="message">The error message.</param>
/// <param name="innerException">Optional inner exception.</param>
public TransientExternalSystemException(string message, Exception? innerException = null)
: base(message, innerException) { }
}
/// <summary>
/// Exception type that signals a permanent failure (should not be retried).
/// </summary>
public class PermanentExternalSystemException : Exception
{
/// <summary>Gets the HTTP status code that caused the permanent failure, if applicable.</summary>
public int? HttpStatusCode { get; }
/// <summary>Initializes a new <see cref="PermanentExternalSystemException"/> with a message, optional HTTP status code, and optional inner exception.</summary>
/// <param name="message">The error message.</param>
/// <param name="httpStatusCode">The HTTP status code that triggered the failure, if available.</param>
/// <param name="innerException">Optional inner exception.</param>
public PermanentExternalSystemException(string message, int? httpStatusCode = null, Exception? innerException = null)
: base(message, innerException)
{
HttpStatusCode = httpStatusCode;
}
}