Hangfire .NET Core database does not exist - PrepareSchemaIfNecessary
Asked Answered
S

3

6

I have a .NET Core web application which is hosted on docker image. This application uses PostgreSQL which is hosted on cloud database service.

We added a Hangfire which will use the same cloud database service as our main application.

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddHangfire(x => x.UsePostgreSqlStorage(ConnectionString));
    ...
}

and in Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseHangfireServer();
    app.UseHangfireDashboard();
    ...
}

Now we have a problem to start the application if our database service is not available (or the database does not exist).

I tried to use:

services.AddHangfire(x => x.UsePostgreSqlStorage(ConnectionString, new PostgreSqlStorageOptions
{
    PrepareSchemaIfNecessary = false
}));

but now I cannot create database schema once the database service is up and running. I could not find any migration scripts for Hangfire.PostgreSql so I can push them with my other business migrations.

I know that for Hangfire.SqlServer there is Install.sql script with which we can create database schema, but for PostgreSql nothing.

In CI/CD pipeline we want to build and run the application first and then to apply migration scripts on the database service, so we don't have the database available when starting the application.

Scriptorium answered 13/3, 2020 at 20:35 Comment(0)
W
2

I ran into that issue, so I ran my app in the debug and went through the whole creating process.

My issue was that I needed to create a schema and give the user permissions to create update delete etc.

The default schema is hangfire, but you can update it like so


config.UsePostgreSqlStorage(connectionString, new PostgreSqlStorageOptions()
                {
                    InvisibilityTimeout = TimeSpan.FromMinutes(5),
                    QueuePollInterval = TimeSpan.FromMilliseconds(200),
                    DistributedLockTimeout = TimeSpan.FromMinutes(1),
                    PrepareSchemaIfNecessary = true,
                    SchemaName = ["Schema"]
                });

Hope that helps.

Wriggler answered 28/7, 2022 at 5:2 Comment(0)
D
0

If database does not exist you can use EF to apply migrations before you use hangfire server in your Startup.cs.

public void ApplyMigrations(AppDbContext context)
{
    try
    {
        if (context.Database.GetPendingMigrations().Any())
        {
            context.Database.Migrate();
        }
    }
    catch (Npgsql.PostgresException ex)
    {
        if (ex.SqlState == "42P07")
        {
            context.Database.EnsureDeleted();
            if (context.Database.GetPendingMigrations().Any())
            {
                context.Database.Migrate();
            }
        }
    }
}

Then use it in Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AppDbContext appDbContext,) 
{
    ...
    ApplyMigrations(appDbContext);
    app.UseHangfireServer();
    app.UseHangfireDashboard();
    ... 
}

Also you should create those migrations using dotnet-ef tool.

Dogma answered 23/4, 2021 at 20:53 Comment(0)
F
0

I faced the same issue and here is my solution :-

In ConfigureServices : services.AddHangfire(config=> { });

In Configure : call this first ApplyAutomaticDatabaseMigration(serviceProvider);

then :

JobStorage.Current = new PostgreSqlStorage(ConfigurationManager.Configuration.SqlConnectionString);

        IBackgroundJobClient backgroundJobs = app.ApplicationServices.GetRequiredService<IBackgroundJobClient>();

`private void ApplyAutomaticDatabaseMigration(IServiceProvider serviceProvider)
    {
        ApplicationDbContext context = serviceProvider.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
        context.Database.EnsureCreated();
    }`

JobStorage.Current should be set before you inject IBackgroundJobClient so we can't inject IBackgroundJobClient in Configure

Another solution :-

simple use another overload of services.AddHangfire like the following

services.AddHangfire((serviceProvider, config) =>
        {
            ApplyAutomaticDatabaseMigration(serviceProvider.CreateScope().ServiceProvider.GetRequiredService<ApplicationDbContext>());
            config.UsePostgreSqlStorage(ConfigurationManager.Configuration.SqlConnectionString);
        });
Fukuoka answered 3/1, 2022 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.