Add EnableRetryOnFailure to handle transient connection failures (57P01 terminating connection)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
@@ -30,7 +31,22 @@ namespace MediaBrowser.Controller.Providers
|
||||
|
||||
public FileSystemMetadata[] GetFileSystemEntries(string path)
|
||||
{
|
||||
return _cache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
|
||||
if (_cache.TryGetValue(path, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = _fileSystem.GetFileSystemEntries(path).ToArray();
|
||||
_cache.TryAdd(path, result);
|
||||
return result;
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// A folder may be deleted between scans; treat it as empty so refresh logic can continue.
|
||||
return Array.Empty<FileSystemMetadata>();
|
||||
}
|
||||
}
|
||||
|
||||
public List<FileSystemMetadata> GetDirectories(string path)
|
||||
|
||||
+6
-64
@@ -277,6 +277,12 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
||||
{
|
||||
npgsqlOptions.MigrationsAssembly(GetType().Assembly.FullName);
|
||||
npgsqlOptions.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
|
||||
|
||||
// Enable automatic retry on transient failures
|
||||
npgsqlOptions.EnableRetryOnFailure(
|
||||
maxRetryCount: 3,
|
||||
maxRetryDelay: TimeSpan.FromSeconds(5),
|
||||
errorCodesToAdd: new[] { "57P01" }); // Add "terminating connection" to retryable errors
|
||||
})
|
||||
.ConfigureWarnings(warnings =>
|
||||
warnings.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning));
|
||||
@@ -301,7 +307,6 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
||||
|
||||
// Start with connection string if provided, then override with individual options
|
||||
NpgsqlConnectionStringBuilder connectionBuilder;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(databaseConfiguration.CustomProviderOptions?.ConnectionString))
|
||||
{
|
||||
// Parse the existing connection string to get all parameters
|
||||
@@ -682,69 +687,6 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually records migrations as applied in the migrations history table.
|
||||
/// This is used to recover from situations where tables were created but the history wasn't updated.
|
||||
/// </summary>
|
||||
/// <param name="context">The database context.</param>
|
||||
/// <param name="migrationIds">List of migration IDs to record.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
private async Task RecordMigrationAsAppliedAsync(JellyfinDbContext context, IList<string> migrationIds, CancellationToken cancellationToken)
|
||||
{
|
||||
var connection = context.Database.GetDbConnection();
|
||||
var wasOpened = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (connection.State != System.Data.ConnectionState.Open)
|
||||
{
|
||||
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
|
||||
wasOpened = true;
|
||||
}
|
||||
|
||||
// Get the current product version from the assembly
|
||||
var productVersion = typeof(JellyfinDbContext).Assembly
|
||||
.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>()?
|
||||
.InformationalVersion ?? "Unknown";
|
||||
|
||||
foreach (var migrationId in migrationIds)
|
||||
{
|
||||
logger.LogInformation("Recording migration '{MigrationId}' as applied", migrationId);
|
||||
|
||||
var insertQuery = @"
|
||||
INSERT INTO ""__EFMigrationsHistory"" (""MigrationId"", ""ProductVersion"")
|
||||
VALUES (@migrationId, @productVersion)
|
||||
ON CONFLICT (""MigrationId"") DO NOTHING";
|
||||
|
||||
await using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = insertQuery;
|
||||
|
||||
var migrationParam = command.CreateParameter();
|
||||
migrationParam.ParameterName = "@migrationId";
|
||||
migrationParam.Value = migrationId;
|
||||
command.Parameters.Add(migrationParam);
|
||||
|
||||
var versionParam = command.CreateParameter();
|
||||
versionParam.ParameterName = "@productVersion";
|
||||
versionParam.Value = productVersion;
|
||||
command.Parameters.Add(versionParam);
|
||||
|
||||
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation("Successfully recorded {Count} migrations in history table", migrationIds.Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (wasOpened)
|
||||
{
|
||||
await connection.CloseAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task RunScheduledOptimisation(CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user