From v1 to v2
Version 2 contains a number of breaking changes from version 1. The core logic and concepts all remain the same in Nexus and this release is mostly about code and project reorganization, removing unnecessary dependencies and updating to .NET 8.
New NuGet package structure
Instead of having the different sub systems such as CommerceMind.Nexus.Jobs
in their own NuGet packages they have been consolidated into the new CommerceMind.Nexus
package and the abstraction packages have been consolidated into CommerceMind.Nexus.Abstractions
.
This reorganization means that many interfaces have been moved to new namespaces. Eg IScheduledJob
which now lives in CommerceMind.Nexus.Abstractions.Jobs
instead of CommerceMind.Nexus.Jobs.Abstractions
. The interface names are still the same, so it should be easy to either search-and-replace the namespaces or let Visual Studio/Rider/etc guide you to the new names.
Another reorganization change in this is that the implementations for the different databases are no longer included in the main packages. Instead they have been extracted into CommerceMind.Nexus.Postgres
, CommerceMind.Nexus.SqlServer
, and CommerceMind.Nexus.Sqlite
. Allowing you to only include the database(s) you want.
New fluent service registration
In v1 there was a number of extension methods on IServiceCollection
that you had to call in a specific order. In v2 this has changed to a fluent registration on IServiceCollection
where the order of which method you call is no longer important.
This is how the v2 registration looks like:
builder.Services.
.AddNexus()
.AddSingleServerInstanceEvents()
.AddFunctions()
.AddScheduledJobs()
.AddQueues()
.AddSqliteConnection()
// Don't forget this one!
.Build()
;
Note that you can still split up your service registration as long as the call to .Build()
is done last, as that will register additional services based on your configuration. You can for example do this:
builder.Services.AddNexus().AddSingleServerInstanceEvents();
builder.Services.AddNexus().AddFunctions();
builder.Services.AddNexus().AddScheduledJobs();
builder.Services.AddNexus().AddQueues();
builder.Services.AddNexus().AddSqliteConnection();
builder.Services.AddNexus().Build();
Each of these lines could be in different projects as well, as long as the call to Build()
happens last. All calls to builder.Services.AddNexus()
will return the same Nexus registration object for that specific service collection. It's also safe to call any method on the Nexus registration object multiple times.
Nexus no longer uses Newtonsoft.Json by default
Instead System.Text.Json
is used by default and the Newtonsoft.Json serializers have been extracted into a separate package called CommerceMind.NewtonsoftJson
which you can use by calling builder.Services.AddNexus().AddNewtonsoftJson()
.
You probably don't need Newtonsoft.Json, this is only if you've modified how the JSON in Nexus is serialized with custom converters.
A notable change here is that the JSON formatting rules for ASP.NET will no longer be applied for queue messages in the API. Instead the JSON formatting rules for Nexus is applied, which means that you might get a response looking like this:
{
"id": 4823771,
"status": "Processed",
"retryCount": 0,
"message": {
"Id": null,
"SomeProperty": null,
"ExampleEnum": "Value1"
}
}
Where the outer object have gotten kebabCase properties but the message object has PascalCase properties. You can control both of these (see docs about JSON) formatting options.
Nexus now requires >= .NET 8
v1 supported .NET 6 but v2 now reqires at least .NET 8. The only thing you need to do is to upgrade your .NET version in your application if you haven't already done so.
Deprecated methods and properties have been removed
Methods and properties that have been deprecated in v1 have been removed in v2. If you upgrade to v1.23.0 and fix all build warnings about obsolete methods and properties you'll automatically be prepared for the removals of them in v2.
Default job history retention is now 30 days
Previously the default was to keep job history in the database forever. To avoid having Nexus growing your database indefinitely the default has been changed to 30 days. You can still configure this just like before, but since you can now have different retention per job the property is now called DefaultHistoricalRunsRetention
:
builder.Services.AddNexus().AddScheduledJobs(options =>
{
options.DefaultHistoricalRunsRetention = TimeSpan.FromDays(10);
});
You set it per job with the [ScheduledJob]
attribute like this:
[ScheduledJob("MyJob", HistoricalRunsRetention = "30.00:00")]
public class MyJob : IScheduledJob
{
...
}
The IEnqueuer and IEnqueuer interfaces have been simplified
Previously IEnqueuer<T>
inherited from IEnqueuer
which it no longer does. In v1 every message type was registered as a IEnqueuer
which means that you could get all enqueuers by requesting IEnumerable<IEnqueuer>
like this:
public class DynamicEnqueuer(IEnumerable<IEnqueuer> enqueuers)
{
public Task EnqueueAsync(IQueueMessage message)
{
var enqueuer = enqueuers.Single(e => e.MessageType == message.GetType());
return enqueuer.EnqueueAsync(message);
}
}
In v2 there is only a single non-generic IEnqueuer
registered which does the above for you. Meaning that you can pass a IQueueMessage
message to it and it will figure out which concrete IEnqueuer<T>
to pass it on to.
Both the IEnqueuer<T>
and IEnqueuer
interfaces have been simplified to take a message and an EnqueueContext
instead of having multiple different overloads for when you want to specify a custom status, a date for when to process it, etc.
So when you did this in v1:
await enqueuer.EnqueueAsync(message, DateTime.UtcNow.AddHours(1));
To enqueue a message to be processed in one hour you now do this:
await enqueuer.EnqueueAsync(message, new EnqueueContext { ProcessAfter = TimeSpan.FromHours(1) });
No longer using Serilog
Nexus previously used Serilog to capture logs happening inside job runs. With v2 it instead has a ILoggerProvider
which is registered by the scheduled job system.
In v2 you can use any logging framework you want as long as it writes to external logging providers. Note that this is turned off by default in Serilog and that you need to enable it, eg like this:
builder.Host.UseSerilog((context, services, configuration) =>
{
configuration.ReadFrom.Configuration(context.Configuration);
// This one is important
}, writeToProviders: true);
If you've used the jobs logging in v2 you also need to remove the Nexus Serilog sink from your configuration:
"Serilog": {
"Using": ["CommerceMind.Nexus.Jobs"],
"WriteTo": [{ "Name": "NexusJobLogs" }]
}
Changes to the IJobLogProvider
interface
For consistencys sake the IJobLogProvider
interface has been renamed to IJobLogReader
since there's also a IJobLogWriter
interface.
And instead of just getting a date to fetch logs newer than Nexus now passes in a date range. You also get the log levels passed as LogLevel
enums rather than strings.
Also note that JobLogEvent.Level
has changed data type from string
to the LogLevel
enum.