Class PgManager
- Namespace
- Solitons.Data.Management.Postgres.Common
- Assembly
- Solitons.Core.dll
Provides an abstract base for managing Postgres databases, including operations for creating, dropping, and upgrading databases, and handling secrets and roles. This class implements the IPgManager interface.
public abstract class PgManager : IPgManager
- Inheritance
-
PgManager
- Implements
- Inherited Members
- Extension Methods
Remarks
Implementing classes must provide their own logic for database connection creation, extraction of connection information, construction of connection strings, execution of database upgrade scripts, managing database upgrade transactions, retrieval of database upgrade scripts, and managing secret information. It also contains robust mechanisms for handling transient database errors via retry policies and leverages the Task Parallel Library and Reactive Extensions for managing asynchronous operations and event-based programs, respectively.
Constructors
PgManager(string, PgManagerConfig, ScriptPriorityComparer)
Initializes a new instance of the PgManager class.
protected PgManager(string connectionString, PgManagerConfig config, ScriptPriorityComparer scriptPriorityComparer)
Parameters
connectionStringstringThe maintenance database connection string for the Postgres database.
configPgManagerConfigThe configuration for the Postgres database.
scriptPriorityComparerScriptPriorityComparerDetermines the order in which the upgrade scripts should be executed.
Properties
ConnectionString
Gets the maintenance database connection string.
protected string ConnectionString { get; }
Property Value
- string
- Provides an abstract base for managing Postgres databases, including operations for creating, dropping, and upgrading databases, and handling secrets and roles. This class implements the interface.
Database
Gets the name of the target Postgres database.
public string Database { get; }
Property Value
- string
- Provides an abstract base for managing Postgres databases, including operations for creating, dropping, and upgrading databases, and handling secrets and roles. This class implements the interface.
Methods
BeginUpgradeTransactionAsync(CancellationToken)
Begins a new database transaction asynchronously as part of the upgrade process.
protected abstract Task<DbTransaction> BeginUpgradeTransactionAsync(CancellationToken cancellation)
Parameters
cancellationCancellationTokenA CancellationToken used to propagate notification that operations should be canceled.
Returns
- Task<DbTransaction>
A Task<TResult> that represents the asynchronous operation. The task result contains a new instance of DbTransaction that is used to perform the upgrade.
Remarks
This abstract method must be implemented in a derived class to define the exact transaction behavior during the upgrade process. A transaction represents a unit of work, and in this case, is used for the database upgrade operation to ensure data consistency and recoverability.
ConnectionTestRetryPolicy(RetryPolicyArgs, CancellationToken)
Defines the retry policy for testing a database connection.
protected virtual IObservable<RetryPolicyArgs> ConnectionTestRetryPolicy(RetryPolicyArgs args, CancellationToken cancellation)
Parameters
argsRetryPolicyArgsThe arguments for the retry policy, including information about the current exception and attempt number.
cancellationCancellationTokenA token that can be used to request the operation to be cancelled.
Returns
- IObservable<RetryPolicyArgs>
An observable stream of RetryPolicyArgs that signals the next attempt should be made if the exception is transient and the attempt number is less than 10.
Remarks
This method will delay the next attempt by a number of milliseconds equal to the current attempt number times 100, up to a maximum of 1000 milliseconds (1 second).
ConstructConnectionString(string, DatabaseConnectionOptions)
Constructs a connection string using the specified template and options.
protected abstract string ConstructConnectionString(string template, PgManager.DatabaseConnectionOptions options)
Parameters
templatestringA string representing the connection string template with placeholders for connection parameters.
optionsPgManager.DatabaseConnectionOptionsA PgManager.DatabaseConnectionOptions object representing the set of connection options to use when constructing the connection string.
Returns
- string
A string representing the constructed connection string.
CreateDbConnection(string)
Creates a new DbConnection object with the specified connection string.
protected abstract DbConnection CreateDbConnection(string connectionString)
Parameters
connectionStringstringThe connection string to use for the new DbConnection object.
Returns
- DbConnection
A new DbConnection object.
CreateDbIfNotExistsAsync(CancellationToken)
Asynchronously creates the database if it doesn't already exist.
protected virtual Task CreateDbIfNotExistsAsync(CancellationToken cancellation)
Parameters
cancellationCancellationTokenA cancellation token that can be used to cancel the operation.
Returns
Remarks
This method opens a new database connection and checks if the database, as defined by the Database property, exists. If it doesn't exist, the method executes a command to create the database.
Subclasses may override this method to provide custom database creation logic. The override should call this base implementation to ensure that the database exists before executing any additional setup logic.
This could be extended to create schemas, extensions, or to assign roles with specific privileges. Remember, any override should first call the base implementation to ensure the existence of the database.
CreateDbRetryPolicy(RetryPolicyArgs, CancellationToken)
Defines the retry policy for creating a database.
protected virtual IObservable<RetryPolicyArgs> CreateDbRetryPolicy(RetryPolicyArgs args, CancellationToken cancellation)
Parameters
argsRetryPolicyArgsThe arguments for the retry policy, including information about the current exception and elapsed time since the first exception.
cancellationCancellationTokenA token that can be used to request the operation to be cancelled.
Returns
- IObservable<RetryPolicyArgs>
An observable stream of RetryPolicyArgs that signals the next attempt should be made if the exception is transient and the elapsed time since the first exception is less than 5 minutes.
Remarks
This method will delay the next attempt by a number of milliseconds equal to the current attempt number times 1000, up to a maximum of 180,000 milliseconds (3 minutes).
CreateRoleRetryPolicy(RetryPolicyArgs, CancellationToken)
Defines the retry policy for creating a database role.
protected virtual IObservable<RetryPolicyArgs> CreateRoleRetryPolicy(RetryPolicyArgs args, CancellationToken cancellation)
Parameters
argsRetryPolicyArgsThe arguments for the retry policy, including information about the current exception and attempt number.
cancellationCancellationTokenA token that can be used to request the operation to be cancelled.
Returns
- IObservable<RetryPolicyArgs>
An observable stream of RetryPolicyArgs that signals the next attempt should be made if the exception is transient and the attempt number is less than 10.
Remarks
This method will delay the next attempt by a number of milliseconds equal to the current attempt number times 300, up to a maximum of 3000 milliseconds (3 seconds).
DropDbAsync(CancellationToken)
Drops the Postgres database with the specified name.
protected virtual Task DropDbAsync(CancellationToken cancellation)
Parameters
cancellationCancellationTokenThe cancellation token to use.
Returns
- Task
- Provides an abstract base for managing Postgres databases, including operations for creating, dropping, and upgrading databases, and handling secrets and roles. This class implements the interface.
DropDbRetryPolicy(RetryPolicyArgs, CancellationToken)
Defines the retry policy for dropping a database.
protected virtual IObservable<RetryPolicyArgs> DropDbRetryPolicy(RetryPolicyArgs arg, CancellationToken cancellation)
Parameters
argRetryPolicyArgsThe arguments for the retry policy, including information about the current exception and attempt number.
cancellationCancellationTokenA token that can be used to request the operation to be cancelled.
Returns
- IObservable<RetryPolicyArgs>
An observable stream of RetryPolicyArgs that signals the next attempt should be made if the exception is transient and the attempt number is less than 10.
Remarks
This method will delay the next attempt by a number of seconds equal to the current attempt number, up to a maximum of 10 seconds.
ExecuteScriptIfApplicableAsync(DbConnection, Script, CancellationToken)
Executes the provided script against the given database connection if certain conditions are met.
protected abstract Task<bool> ExecuteScriptIfApplicableAsync(DbConnection connection, Script script, CancellationToken cancellation)
Parameters
connectionDbConnectionThe database connection on which the script will be executed.
scriptScriptThe script to potentially be executed.
cancellationCancellationTokenA cancellation token that can be used to cancel the operation.
Returns
- Task<bool>
A Task that represents the asynchronous operation. The result of the task indicates whether the script was executed.
Remarks
This method is designed to ensure the idempotency of setup scripts and one-time execution of migration scripts. Setup scripts are idempotent, meaning they can be run multiple times without causing negative effects or changing the result beyond the initial application. Migration scripts, on the other hand, are designed to be executed only once. The decision of whether or not to execute the script should be implemented in this method.
ExtractConnectionInfo(string)
Extracts the connection information from the specified connection string.
protected abstract PgConnectionInfo ExtractConnectionInfo(string connectionString)
Parameters
connectionStringstringThe connection string from which to extract the connection information.
Returns
- PgConnectionInfo
The extracted connection information.
GenRandomPassword()
Generates a random password.
protected virtual string GenRandomPassword()
Returns
- string
A random password.
GetSecret(string, CancellationToken)
Fetches the value of a secret, such as a password or a connection string, from a secure storage location.
protected IObservable<string> GetSecret(string secretKey, CancellationToken cancellation)
Parameters
secretKeystringThe unique identifier of the secret to be retrieved.
cancellationCancellationTokenA CancellationToken that can be used to cancel the operation.
Returns
- IObservable<string>
An observable sequence that contains the value of the secret.
Remarks
This method uses an asynchronous design pattern based on the IObservable<T> interface. It returns immediately with an IObservable<T> that can be used to track the completion of the operation and handle any exceptions that might occur. The secret storage location and the mechanism to retrieve the secret are implementation-dependent.
GetSecretIfExistsAsync(string, CancellationToken)
Gets the connection string for the specified role if it exists.
protected abstract Task<string?> GetSecretIfExistsAsync(string secretKey, CancellationToken cancellation)
Parameters
secretKeystringThe secret key.
cancellationCancellationTokenThe cancellation token to use.
Returns
GetUpgradeScripts()
Gets the collection of scripts that should be executed for the database upgrade process.
protected abstract IEnumerable<Script> GetUpgradeScripts()
Returns
- IEnumerable<Script>
An IEnumerable<T> of Script that represents the set of upgrade scripts.
Remarks
This abstract method should be implemented in a derived class to provide the specific upgrade scripts needed for the database. These scripts are executed during the upgrade process and could include operations such as data transformations, table alterations, or new data additions. The order of scripts in the returned sequence may influence the upgrade process, thus implementors should ensure their correct order.
IsAuthorizedAsync(DbConnection, CancellationToken)
Asynchronously checks whether the current Postgres user is authorized to create databases and roles.
public static Task<bool> IsAuthorizedAsync(DbConnection connection, CancellationToken cancellation = default)
Parameters
connectionDbConnectionThe active database connection to use for the check.
cancellationCancellationTokenOptional cancellation token that can be used to cancel the operation. Defaults to none.
Returns
- Task<bool>
A task representing the asynchronous operation. The task result contains a boolean indicating whether the current user is authorized to create databases and roles.
Exceptions
- Exception
Throws an exception if the query operation fails.
OnInvalidConnectionStringAsync(string, string, CancellationToken)
Handles the case when an invalid connection string is encountered.
protected virtual Task OnInvalidConnectionStringAsync(string error, string role, CancellationToken cancellation)
Parameters
errorstringThe error message.
rolestringThe role associated with the connection string.
cancellationCancellationTokenThe cancellation token to use.
Returns
OnUpgradedAsync(DbTransaction, CancellationToken)
Asynchronously handles the post-upgrade actions within a transaction scope.
protected virtual Task OnUpgradedAsync(DbTransaction transaction, CancellationToken cancellation)
Parameters
transactionDbTransactionThe DbTransaction in which the upgrade has been performed.
cancellationCancellationTokenA CancellationToken used to propagate notification that operations should be canceled.
Returns
- Task
A Task that represents the asynchronous operation. The task result indicates that the transaction has been committed.
Remarks
This method gets called after the database upgrade is done. By default, it commits the database transaction, finalizing the changes. Override this method to add additional steps after the upgrade process or to alter the default transaction behavior.
OnUpgradingAsync(CancellationToken)
Called during the upgrade process and can be overridden to implement custom upgrade logic.
protected virtual Task OnUpgradingAsync(CancellationToken cancellation)
Parameters
cancellationCancellationTokenA cancellation token that can be used to cancel the operation.
Returns
- Task
A Task that represents the completion of this method. This base implementation immediately returns a completed task.
PerformPostUpgradeTestsAsync(CancellationToken)
Executes an optional set of tests against the database.
protected virtual Task PerformPostUpgradeTestsAsync(CancellationToken cancellation)
Parameters
cancellationCancellationTokenAn instance of CancellationToken used to propagate notification that operations should be canceled.
Returns
Remarks
This method provides a hook to perform any necessary tests against the database once the upgrade process has been completed. It is empty by default, and can be overridden in a derived class to implement specific tests. Note that this method is run asynchronously, so any implemented tests should also be asynchronous. If no tests are required, the method can be left as it is, and it will simply return a completed task when called.
RegisterLoginIfNotExistsAsync(PgConnectionInfo, string, string, CancellationToken)
Asynchronously registers a new database login if it doesn't already exist.
protected virtual Task<bool> RegisterLoginIfNotExistsAsync(PgConnectionInfo maintenanceDbConnectionParams, string username, string secretName, CancellationToken cancellation)
Parameters
maintenanceDbConnectionParamsPgConnectionInfoThe connection parameters for the database maintenance operations.
usernamestringThe username for the new login.
secretNamestringThe name of the secret to be stored.
cancellationCancellationTokenA cancellation token that can be used to cancel the operation.
Returns
- Task<bool>
A Task that represents the asynchronous operation. The task result contains a boolean indicating whether a new secret was generated.
Remarks
This method checks the validity of the provided secret. If it is not valid or does not exist, it generates a new secret and creates a new role with the given username and new secret in the database. If the role already exists, it updates the login password of the role with the new secret.
The newly generated secret is then saved and the method returns whether a new secret was generated.
Note: Exceptions during the secret validity check are caught and logged as a warning. In such cases, the method proceeds to generate a new secret.
SaveSecretAsync(string, string, CancellationToken)
Saves the specified secret value with the specified key.
protected abstract Task SaveSecretAsync(string secretKey, string secretValue, CancellationToken cancellation)
Parameters
secretKeystringThe key for the secret value.
secretValuestringThe secret value to save.
cancellationCancellationTokenThe cancellation token to use.
Returns
- Task
- Provides an abstract base for managing Postgres databases, including operations for creating, dropping, and upgrading databases, and handling secrets and roles. This class implements the interface.
TestRetryPolicy(RetryPolicyArgs, CancellationToken)
Defines the retry policy for running post-upgrade tests on the database.
protected virtual IObservable<RetryPolicyArgs> TestRetryPolicy(RetryPolicyArgs arg, CancellationToken cancellation)
Parameters
argRetryPolicyArgsThe retry policy arguments, which include details about the current retry attempt, such as the current retry count, the exception that caused the retry, and the delay before the next retry.
cancellationCancellationTokenA CancellationToken that can be used to cancel the operation.
Returns
- IObservable<RetryPolicyArgs>
An observable sequence that notifies observers about the retry policy parameters for each new retry attempt.
Remarks
This method is typically used in conjunction with the PerformPostUpgradeTestsAsync(CancellationToken) method. If PerformPostUpgradeTestsAsync(CancellationToken) encounters an exception, this method determines whether to retry the test, and if so, the delay before the next attempt. By overriding this method in a derived class, you can customize the retry behavior for post-upgrade testing.