fix(ha): PostgreSQL migration backup no-op + URI connection string support
- MigrationBackupFast/RestoreBackupFast/DeleteBackup return no-ops for PostgreSQL; pre-migration backups are handled by jellyfin-pg-backup CronJob, not the automated backup path that throws NotSupportedException - ServiceCollectionExtensions: detect postgresql:// / postgres:// URI format in POSTGRES_CONNECTION_STRING and convert to ADO.NET key=value format before passing to NpgsqlDataSourceBuilder (which requires it) Closes startup crash: 'Automated migration backups are not supported for PostgreSQL' on first boot with a fresh database.
This commit is contained in:
@@ -149,6 +149,23 @@ public static class ServiceCollectionExtensions
|
||||
"No PostgreSQL connection string found. Set the POSTGRES_CONNECTION_STRING environment variable, " +
|
||||
"or provide it via CustomProviderOptions.Options[\"ConnectionString\"] or CustomProviderOptions.ConnectionString.");
|
||||
|
||||
// Support postgresql:// / postgres:// URI format (e.g. DATABASE_URL convention).
|
||||
// NpgsqlDataSourceBuilder requires ADO.NET key=value format; convert if needed.
|
||||
if (connectionString.StartsWith("postgresql://", StringComparison.OrdinalIgnoreCase)
|
||||
|| connectionString.StartsWith("postgres://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var uri = new Uri(connectionString);
|
||||
var userInfoParts = uri.UserInfo.Split(':', 2);
|
||||
connectionString = new NpgsqlConnectionStringBuilder
|
||||
{
|
||||
Host = uri.Host,
|
||||
Port = uri.Port > 0 ? uri.Port : 5432,
|
||||
Database = uri.AbsolutePath.TrimStart('/'),
|
||||
Username = userInfoParts.Length > 0 ? Uri.UnescapeDataString(userInfoParts[0]) : null,
|
||||
Password = userInfoParts.Length > 1 ? Uri.UnescapeDataString(userInfoParts[1]) : null,
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
|
||||
|
||||
dataSourceBuilder.ConnectionStringBuilder.MinPoolSize = GetPoolOption(options, "MinPoolSize", 2);
|
||||
|
||||
+11
-5
@@ -15,8 +15,9 @@ namespace Jellyfin.Database.Providers.PostgreSQL;
|
||||
[JellyfinDatabaseProviderKey("Jellyfin-PostgreSQL")]
|
||||
public sealed class PostgreSqlDatabaseProvider : IJellyfinDatabaseProvider
|
||||
{
|
||||
private const string BackupNotSupportedMessage =
|
||||
"Automated migration backups are not supported for PostgreSQL. Use the jellyfin-pg-backup CronJob for nightly S3 backups.";
|
||||
// Sentinel returned by MigrationBackupFast to signal that no file backup was
|
||||
// created (PostgreSQL backups are handled externally by jellyfin-pg-backup CronJob).
|
||||
private const string NoAutomatedBackupKey = "postgresql-no-automated-backup";
|
||||
|
||||
private readonly NpgsqlDataSource _dataSource;
|
||||
|
||||
@@ -69,19 +70,24 @@ public sealed class PostgreSqlDatabaseProvider : IJellyfinDatabaseProvider
|
||||
/// <inheritdoc/>
|
||||
public Task<string> MigrationBackupFast(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotSupportedException(BackupNotSupportedMessage);
|
||||
// PostgreSQL pre-migration backups are handled externally by the
|
||||
// jellyfin-pg-backup CronJob. Return a sentinel so callers know no
|
||||
// file backup was created and the migration can proceed safely.
|
||||
return Task.FromResult(NoAutomatedBackupKey);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task RestoreBackupFast(string key, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotSupportedException(BackupNotSupportedMessage);
|
||||
// No automated backup was taken; nothing to restore.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task DeleteBackup(string key)
|
||||
{
|
||||
throw new NotSupportedException(BackupNotSupportedMessage);
|
||||
// No automated backup was taken; nothing to delete.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
Reference in New Issue
Block a user