In-memory queues

Queues in Nexus are backed by a database but in some cases you want to squeeze the last bit of performance out of your queues and then the overhead of a database can become too much for certain use cases, or if you need to relieve your database of the work needed to handle some very busy queues.

For those scenarios Nexus lets you have in-memory queues without the overhead of reading and writing to a database first. Note however that this only works if you only deploy Nexus to a single server. See the section below about single-server use. You can however allow other servers to enqueue but only if you use IApiEnqueuer to enqueue through the API to the single server hosting the API and the memory queue(s).

Creating a memory queue

You create a memory queue just like any other queue by creating a class that implements IQueueMessage or IQueueMessageWithId:

[Queue("example_memory", InMemory = true)]
public class ExampleMemoryQueueMessage : IQueueMessage
{
    // Properties here
}

When you set InMemory = true in the attribute it gets registered as a memory queue. Note that you can switch back and forth between having a queue as an in-memory queue or not because an in-memory queue will use its database queue as fallback storage to ensure that messages aren't lost because of deploy or application restarts.

Messages and message changes are scheduled to be persisted to the database as soon as possible, but it's done on a background thread. The in-memory queue registers a listener for application shutdown to prevent the application from shutting down before all changes are persisted.

Durability

Even if the queue is in-memory Nexus still persists changes to it in the background in order for queue items to survive a deploy and any application crash.

The queue item change are persisted as fast as possible on a background thread so the durability guarantees are very close to the guarantees of database queues. All changes are synchronously flushed to the database when the application starts to shutdown.

The only time you would risk data loss if you have a large amount of messages coming in at the same time as a power outage or if your host doesn't give the application enough time to shut down gracefully.

Fallback storage

The in-memory queue will fallback to it's own regular database table by default which makes the transition from a non-memory queue to an in-memory queue smooth. But if you want to use an in-memory queue to lessen the load on your database it doesn't have the intended effect. In that case you can explicitly use the Sqlite driver and use Sqlite tables as fallback storage by installing the CommerceMind.Nexus.Sqlite NuGet package and adding this in your Program.cs:

builder.Services
    .AddNexus()
    .AddSqliteMemoryQueueFallbackStorage();

If using disk as fallback storage isn't an option for you it's possible to create your own implementation of the interface IMemoryQueueFallbackStorage and register it in the service collection.

Single server use only

In-memory queues can generally only be used if you only have a single server/instance running Nexus. Even if changes to an in-memory queue is persisted to storage Nexus won't read from the storage except during initialization.

You can use in-memory queues in a multi-instance application if the queues are local to that instance and messages in the same queue have no effect on messages in other instances in terms of sort order or processing side effects. In this case however you must implement your own IMemoryQueueFallbackStorage as the built in implementation uses a memory counter to increment assign queue item ids.

If you're using a hosting service such as Azure App Service you probably can't use in-memory queues unless you make sure to stop the application before starting a deploy as the default in Azure App Service is to bring up a parallel deployment slot and swap with the live slot. Which means that during deploy you will have multiple instances running. If this is an issue for your application will depend on how you use the queues.

Application shutdown

In-memory queues registers a callback on the applications stopping token (CancellationToken) and performs a synchronous flush of all pending changes to the fallback storage. Nexus will also attempt to stop all jobs when shutdown starts and won't start any jobs after that.

But it's up to you not to enqueue to memory queues after shutdown has started. If you do you will risk enqueueing a message that doesn't have time to be persisted before the process exits.

In-memory queues and transactions

In-memory queues does not offer a way to integrate with the transaction support in DbConnectionScope. All changes to an in-memory queue are visible immediately to the whole application, and changes are sent to the fallback storage explicitly without transaction support to not accidentally enlist those queries in unrelated transactions.

If you need transaction support you should enqueue your messages to a memory list first and then send them to Nexus after your database transaction has successfully completed.