Database

The system uses a SQL database to store meta data and queue messages. At the time of writing we support SQLite, Postgres and SQL Server. Feel free to reach out to us if you need support for another database engine like MySQL or MariaDB.

The default configuration is to use SQLite which is great for quickly getting up and running and for lower environments like a test environment. It's however not recommended to use SQLite for a production environment under heavy load.

Configuring which database to use

Open your Program.cs and go to these lines:

builder.Services.AddNexusFunctions();
builder.Services.AddNexusScheduledJobs();
builder.Services.AddNexusQueues();

Both these takes an optional lamda to set configuration parameters. So if we want to use Postgres or SQL Server instead, we need to update the code to this:

var databaseEngine = DatabaseEngine.Postgres; // Or DatabaseEngine.SqlServer
builder.Services.AddNexusFunctions(options =>
{
    options.DatabaseEngine = databaseEngine;
});
builder.Services.AddNexusScheduledJobs(options =>
{
    options.DatabaseEngine = databaseEngine;
});
builder.Services.AddNexusQueues(options =>
{
    options.DatabaseEngine = databaseEngine;
});

By default the system will look call IConfiguration.GetConnectionString("postgres"), IConfiguration.GetConnectionString("sqlserver") or IConfiguration.GetConnectionString("sqlite") to get the connection string to the database. If that doesn't work for you can register a lamda to provide your connection string like this:

builder.Services.AddNexusPostgresConnection(options =>
{
    options.ConnectionStringLoader = serviceProvider =>
    {
        // Find and return your connection string here
    };
});

// Or:
builder.Services.AddNexusSqlServerConnection(options =>
{
    options.ConnectionStringLoader = serviceProvider =>
    {
        // Find and return your connection string here
    };
});

// Or:
builder.Services.AddNexusSqliteConnection(options =>
{
    options.ConnectionStringLoader = serviceProvider =>
    {
        // Find and return your connection string here
    };
});

Make sure to add this line before calling the other initialization methods like AddNexusScheduledJobs() and AddNexusQueues().

Using a ConnectionStringLoader

When you use ConnectionStringLoader you need to make sure that it's a very fast operations as the loader will be called every time Nexus runs a database query. You need to make sure to cache the value if you fetch it from an external store such as Azure KeyVault.

Controlling the connection

By default Nexus will open and close database connections for almost every query, and rely on the underlying connection pooling. In some cases you might want to have more control over the connection such as if you want to include the Nexus queries inside a transaction.

One option is to use a DbConnectionScope like this:

public async Task RunAsync(IEnqueuer<SomeMessage> enqueuer)
{
    var dbConnection = CreateDbConnection();

    using (var transaction = connection.BeginTransaction())
    using (var _ = new DbConnectionScope(connection, transaction))
    {
        // The enqueuer will now use dbConnection to run the database queries to enqueue the message
        await enqueuer.EnqueueAsync(new SomeMessage());

        transaction.Commit();
    }

    // This message will be enqueued using the default way with a new connection
    await enqueuer.EnqueueAsync(new SomeMessage());
}

The effect of this is that any Nexus services inside the using block will use the dbConnection object rather than creating new connections. Which means that you can start a transaction in dbConnection and automatically have all Nexus operations inside the using block be a part of that transaction.

Database maintenance

Nexus includes two jobs that are enabled by default. One job is called RebuildDatabaseIndexes and will rebuild database indexes for Postgres and SQL Server. It's scheduled to run daily at midnight. If you're using SQLite this job won't do anything as it's not needed to rebuild SQLite indexes.

By default this job will only rebuild indexes in tables created by Nexus. If you want it to rebuild indexes for all tables in the database you can can pass an option to AddNexusPostgresConnection() or AddNexusSqlServerConnection():

builder.Services.AddNexusPostgresConnection(options =>
{
    options.LimitDatabaseMaintenanceToNexusTables = false;
});

// Or:
builder.Services.AddNexusSqlServerConnection(options =>
{
    options.LimitDatabaseMaintenanceToNexusTables = false;
});

The other job is called RunDatabaseMaintenanceJob and is also enabled by default and but not scheduled. For Postgres that will run VACUUM and then ANALYZE. If you're using SQL Server this job won't do anything as SQL Server has automatic update of query statistics. If you're using SQLite this job will not do anything either.

Remove database maintenance jobs

If you want to completely hide these jobs you can pass a filter lambda when you register the jobs system to exclude these jobs like this:

builder.Services.AddNexusScheduledJobs(options =>
{
    options.ScheduledJobFilter = jobType => jobType.Name != "RebuildDatabaseIndexes" && jobType.Name != "RunDatabaseMaintenanceJob";
});

If you want to run the jobs but do something different than the defaults you can create your own implementation of the IDatabaseMaintenanceService interface and register it with the service provider like this:

builder.Services.AddSingleton<IDatabaseMaintenanceService, MyDatabaseMaintenanceService>();

Using another database engine

If you want to use another database engine such as MySQL or MariaDB you can always implement it and open a PR to the Github repository. If you don't have access yet to the repository just ping us! Another option is of course to hire us to implement it for you.