| | | 1 | | namespace Elsa.Resilience; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Default implementation that detects common transient exceptions from the .NET framework and common patterns. |
| | | 5 | | /// </summary> |
| | | 6 | | public class DefaultTransientExceptionStrategy : ITransientExceptionStrategy |
| | | 7 | | { |
| | 2 | 8 | | private static readonly HashSet<string> TransientExceptionTypeNames = new(StringComparer.OrdinalIgnoreCase) |
| | 2 | 9 | | { |
| | 2 | 10 | | // Common framework exceptions |
| | 2 | 11 | | "HttpRequestException", |
| | 2 | 12 | | "TimeoutException", |
| | 2 | 13 | | "TaskCanceledException", |
| | 2 | 14 | | "IOException", |
| | 2 | 15 | | "SocketException", |
| | 2 | 16 | | "EndOfStreamException", |
| | 2 | 17 | | |
| | 2 | 18 | | // Database-related transient exceptions (by name, not type reference) |
| | 2 | 19 | | "DbException", |
| | 2 | 20 | | "SqlException", |
| | 2 | 21 | | "NpgsqlException", |
| | 2 | 22 | | "MongoConnectionException", |
| | 2 | 23 | | "MongoExecutionTimeoutException", |
| | 2 | 24 | | "MongoNodeIsRecoveringException", |
| | 2 | 25 | | "MongoNotPrimaryException", |
| | 2 | 26 | | "MySqlException", |
| | 2 | 27 | | |
| | 2 | 28 | | // Network-related exceptions |
| | 2 | 29 | | "HttpIOException", |
| | 2 | 30 | | "WebException", |
| | 2 | 31 | | }; |
| | | 32 | | |
| | 2 | 33 | | private static readonly HashSet<string> TransientExceptionMessagePatterns = new(StringComparer.OrdinalIgnoreCase) |
| | 2 | 34 | | { |
| | 2 | 35 | | "timeout", |
| | 2 | 36 | | "timed out", |
| | 2 | 37 | | "connection reset", |
| | 2 | 38 | | "connection refused", |
| | 2 | 39 | | "broken pipe", |
| | 2 | 40 | | "network", |
| | 2 | 41 | | "end of stream", |
| | 2 | 42 | | "attempted to read past the end", |
| | 2 | 43 | | "the connection is closed", |
| | 2 | 44 | | "connection is not open", |
| | 2 | 45 | | "failed to connect", |
| | 2 | 46 | | "no connection could be made", |
| | 2 | 47 | | "an existing connection was forcibly closed", |
| | 2 | 48 | | }; |
| | | 49 | | |
| | | 50 | | /// <inheritdoc /> |
| | | 51 | | public bool IsTransient(Exception exception) |
| | | 52 | | { |
| | | 53 | | // Check if the exception type name matches any known transient exception |
| | 43 | 54 | | var exceptionTypeName = exception.GetType().Name; |
| | 43 | 55 | | if (TransientExceptionTypeNames.Contains(exceptionTypeName)) |
| | 21 | 56 | | return true; |
| | | 57 | | |
| | | 58 | | // Check if the exception message contains any transient patterns |
| | 22 | 59 | | var message = exception.Message; |
| | | 60 | | |
| | 22 | 61 | | return !string.IsNullOrEmpty(message) && |
| | 22 | 62 | | TransientExceptionMessagePatterns |
| | 195 | 63 | | .Any(pattern => message.Contains(pattern, StringComparison.OrdinalIgnoreCase)); |
| | | 64 | | } |
| | | 65 | | } |