Add EnableRetryOnFailure to handle transient connection failures (57P01 terminating connection)
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
@@ -30,7 +31,22 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
|
|
||||||
public FileSystemMetadata[] GetFileSystemEntries(string path)
|
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)
|
public List<FileSystemMetadata> GetDirectories(string path)
|
||||||
|
|||||||
+6
-64
@@ -277,6 +277,12 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
|||||||
{
|
{
|
||||||
npgsqlOptions.MigrationsAssembly(GetType().Assembly.FullName);
|
npgsqlOptions.MigrationsAssembly(GetType().Assembly.FullName);
|
||||||
npgsqlOptions.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
|
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 =>
|
.ConfigureWarnings(warnings =>
|
||||||
warnings.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning));
|
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
|
// Start with connection string if provided, then override with individual options
|
||||||
NpgsqlConnectionStringBuilder connectionBuilder;
|
NpgsqlConnectionStringBuilder connectionBuilder;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(databaseConfiguration.CustomProviderOptions?.ConnectionString))
|
if (!string.IsNullOrWhiteSpace(databaseConfiguration.CustomProviderOptions?.ConnectionString))
|
||||||
{
|
{
|
||||||
// Parse the existing connection string to get all parameters
|
// 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/>
|
/// <inheritdoc/>
|
||||||
public async Task RunScheduledOptimisation(CancellationToken cancellationToken)
|
public async Task RunScheduledOptimisation(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user