# Scheduling

Time is important, particularly in distributed applications. Sophisticated systems need to schedule things, and MassTransit has extensive scheduling support.

MassTransit supports two different methods of message scheduling:

  1. Scheduler-based, using either Quartz.NET or Hangfire, where the scheduler runs in a service and schedules messages using a queue.
  2. Transport-based, using the transports built-in message scheduling/delay capabilities. In some cases, such as RabbitMQ, this requires an additional plug-in to be installed and configured.

Recurring schedules are only supported by scheduler-based solutions (Option 1).

# Configuration

Depending upon the scheduling method used, the bus must be configured to use the appropriate scheduler.

# Using the message scheduler

To use the message scheduler (outside of a consumer), use IMessageScheduler from the container.

# Quartz.NET

To use Quartz.NET, an instance of Quartz.NET must be running and configured to use the message broker.

# Internal Quartz.NET instance

MassTransit is able to connect to an existing Quartz.NET instance running in the same executable.

namespace SchedulingInternalInstance;

using System;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Quartz;

public class Program
{
    public static void Main()
    {
        const string schedulerQueueName = "scheduler";
        var schedulerUri = new Uri($"queue:{schedulerQueueName}");

        var services = new ServiceCollection();

        services.AddQuartz(q =>
        {
            q.UseMicrosoftDependencyInjectionJobFactory();
        });

        services.AddMassTransit(x =>
        {
            x.AddMessageScheduler(schedulerUri);

            x.AddPublishMessageScheduler();

            x.AddQuartzConsumers();

            x.UsingRabbitMq((context, cfg) =>
            {
                cfg.UsePublishMessageScheduler();

                cfg.ConfigureEndpoints(context);
            });
        });
    }
}

WARNING

The code above asumes Quartz.NET is already configured using dependency injection.

# External Quartz.NET instance

MassTransit provides a Docker Image (opens new window) with Quartz.NET ready-to-run using SQL Server. A complementary SQL Server Image (opens new window) configured to run with Quartz.NET is also available. Combined, these images make getting started with Quartz easy.

# Testing

Quartz.NET can also be configured in-memory, which is great for unit testing.

Uses MassTransit.Quartz (opens new window)

namespace SchedulingInMemory;

using System;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main()
    {
        var services = new ServiceCollection();

        services.AddMassTransit(x =>
        {
            x.AddMessageScheduler(new Uri("queue:scheduler"));

            x.UsingRabbitMq((context, cfg) =>
            {
                cfg.UseInMemoryScheduler("scheduler");

                cfg.ConfigureEndpoints(context);
            });
        });
    }
}

The UseInMemoryScheduler method initializes Quartz.NET for standalone in-memory operation, and configures a receive endpoint named scheduler. The AddMessageScheduler adds IMessageScheduler to the container, which will use the same scheduler endpoint.

WARNING

Using the in-memory scheduler uses non-durable storage. If the process terminates, any scheduled messages will be lost, immediately, never to be found again. For any production system, using a standalone service is recommended with persistent storage.

# Transport-based

To configure transport-based message scheduling, refer to the transport-specific section for details.