private Task <bool> ExistsAsync(bool retryOnNotExists, CancellationToken cancellationToken)
        => Dependencies.ExecutionStrategyFactory.Create().ExecuteAsync(
            DateTime.UtcNow + RetryTimeout, async(giveUp, ct) =>
        {
            while (true)
            {
                try
                {
                    using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
                    {
                        await _connection.OpenAsync(ct, errorsExpected: true);

                        _connection.Close();
                    }
                    return(true);
                }
                catch (PostgresException e)
                {
                    if (!retryOnNotExists &&
                        IsDoesNotExist(e))
                    {
                        return(false);
                    }

                    if (DateTime.UtcNow > giveUp ||
                        !RetryOnExistsFailure(e))
                    {
                        throw;
                    }

                    await Task.Delay(RetryDelay, ct);
                }
            }
        }, cancellationToken);
Exemplo n.º 2
0
        public override async Task CreateTablesAsync(CancellationToken cancellationToken = default)
        {
            var operations = Dependencies.ModelDiffer.GetDifferences(null, Dependencies.Model.GetRelationalModel());
            var commands   = Dependencies.MigrationsSqlGenerator.Generate(operations, Dependencies.Model);

            // If a PostgreSQL extension, enum or range was added, we want Npgsql to reload all types at the ADO.NET level.
            var reloadTypes =
                operations.OfType <AlterDatabaseOperation>()
                .Any(o =>
                     o.GetPostgresExtensions().Any() ||
                     o.GetPostgresEnums().Any() ||
                     o.GetPostgresRanges().Any());

            try
            {
                await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(commands, _connection,
                                                                                 cancellationToken);
            }
            catch (PostgresException e) when(
                e.SqlState == "23505" && e.ConstraintName == "pg_type_typname_nsp_index"
                )
            {
                // This occurs when two connections are trying to create the same database concurrently
                // (happens in the tests). Simply ignore the error.
            }

            if (reloadTypes)
            {
                await _connection.OpenAsync(cancellationToken);

                try
                {
                    // TODO: Not async
                    ((NpgsqlConnection)_connection.DbConnection).ReloadTypes();
                }
                catch
                {
                    _connection.Close();
                }
            }
        }