> For the complete documentation index, see [llms.txt](https://brightercommand.gitbook.io/paramore-brighter-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://brightercommand.gitbook.io/paramore-brighter-documentation/scheduler/switchingschedulers.md).

# Switching Schedulers

This page shows you how to move an existing application from one Brighter scheduler to another.

> **How-to** · Applies to **Brighter V10** · Prerequisites: [Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport.md)

This page shows you how to move an existing application from one Brighter scheduler to another. Each scheduler documents its own configuration in full; what follows is only what changes when you swap one for another. For help deciding which scheduler to move to, see [Choosing a Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport.md#choosing-a-scheduler).

## Why You Would Switch Schedulers

The common case is leaving the InMemory scheduler behind. When moving to production, replace InMemory with a durable scheduler: it holds its timers in process memory, so a restart loses every scheduled message.

The other cases are environmental. You move to [AWS Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/awsscheduler.md) or [Azure Service Bus](/paramore-brighter-documentation/scheduler/brighterschedulersupport/azurescheduler.md) when you want the platform to run the schedule rather than your own database, and between [Hangfire](/paramore-brighter-documentation/scheduler/brighterschedulersupport/hangfirescheduler.md) and [Quartz](/paramore-brighter-documentation/scheduler/brighterschedulersupport/quartzscheduler.md) when you need something the other one has — a dashboard, or a strong-named assembly.

## Switching Schedulers: What Changes and What Does Not

**No code changes required** - just swap the scheduler factory!

Your handlers, your commands and your calls to `SendAsync`, `PostAsync` and `PublishAsync` are all unchanged. The scheduler is supplied by a factory passed to `UseScheduler`, and that factory is the only thing you replace.

Before, on the InMemory scheduler:

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;

services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(new InMemorySchedulerFactory())
    .AutoFromAssemblies();
```

Before, on Quartz:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.Quartz;
using Quartz;

// Before (Quartz)
services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(provider =>
    {
        var schedulerFactory = provider.GetRequiredService<ISchedulerFactory>();
        return new QuartzSchedulerFactory(
            schedulerFactory.GetScheduler().GetAwaiter().GetResult()
        );
    })
    .AutoFromAssemblies();
```

What follows replaces the `UseScheduler` call, and nothing else.

## Switching to a Production Scheduler

### Switching to Hangfire

Hangfire needs its own storage, its server, and the job type Brighter schedules against, registered alongside the factory:

```csharp
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.Hangfire;

services.AddHangfire(config => config.UseSqlServerStorage(connectionString));
services.AddHangfireServer();
services.AddSingleton<BrighterHangfireSchedulerJob>();

services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(provider =>
    {
        // Resolve Hangfire's client first: that initialises its storage (Brighter#4600)
        var client = provider.GetRequiredService<IBackgroundJobClientV2>();
        return new HangfireMessageSchedulerFactory { Client = client };
    })
    .AutoFromAssemblies();
```

### Switching to Quartz

Quartz supplies its own `IScheduler`, which `QuartzSchedulerFactory` wraps, so the factory is resolved from the service provider rather than constructed directly:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.Quartz;
using Quartz;

services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(provider =>
    {
        var factory = provider.GetRequiredService<ISchedulerFactory>();
        var scheduler = factory.GetScheduler().GetAwaiter().GetResult();
        return new QuartzSchedulerFactory(scheduler);
    })
    .AutoFromAssemblies();
```

### Switching to AWS Scheduler

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.AWS;

// After (Production on AWS)
services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(new AwsSchedulerFactory(awsConnection, "scheduler-role")
    {
        SchedulerTopicOrQueue = new RoutingKey("scheduler-topic"),
        OnConflict = OnSchedulerConflict.Overwrite
    })
    .AutoFromAssemblies();
```

**Benefits of moving to AWS Scheduler**:

* No database required
* No server maintenance
* Automatic scaling
* Pay-per-use pricing

### Switching to Azure Service Bus

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.Azure;

// After (Production on Azure)
services.AddBrighter(options =>
    {
        // ...
    })
    .UseScheduler(new AzureServiceBusSchedulerFactory(
        clientProvider,
        new RoutingKey("brighter-scheduler-topic")
    ))
    .AutoFromAssemblies();
```

**Additional Setup Required**:

* Configure FireAzureScheduler subscription in Dispatcher
* Create scheduler topic in Azure Service Bus
* Configure RBAC permissions

**Benefits of moving to Azure Service Bus Scheduler**:

* Simpler (no separate scheduler infrastructure)
* Native Azure integration
* Reduced operational complexity
* No database required

**Considerations**:

* Must configure FireAzureScheduler subscription
* No reschedule support (cancel + schedule instead)
* Requires FireAzureScheduler topic in Service Bus

## Running Two Schedulers During a Transition

You can run both schedulers during transition, choosing between them at startup, so the change can be rolled forward and back without a redeployment:

```csharp
using Hangfire;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.Hangfire;
using Paramore.Brighter.MessageScheduler.Quartz;
using Quartz;

// Run both schedulers temporarily
var brighter = services.AddBrighter(options =>
    {
        // ...
    })
    .AutoFromAssemblies();

// Choose based on feature flag or configuration
if (configuration.GetValue<bool>("UseQuartz"))
{
    brighter.UseScheduler(provider =>
    {
        var factory = provider.GetRequiredService<ISchedulerFactory>();
        return new QuartzSchedulerFactory(factory.GetScheduler().GetAwaiter().GetResult());
    });
}
else
{
    brighter.UseScheduler(provider =>
    {
        // Resolve Hangfire's client first: that initialises its storage (Brighter#4600)
        var client = provider.GetRequiredService<IBackgroundJobClientV2>();
        return new HangfireMessageSchedulerFactory { Client = client };
    });
}
```

Reverse the condition to migrate the other way.

## Further Reading

* [Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport.md) - What scheduling is, and choosing a scheduler
* [Scheduling a Message](/paramore-brighter-documentation/scheduler/schedulingamessage.md) - Code and configuration examples for scheduling
* [Hangfire Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/hangfirescheduler.md) - Hangfire scheduler configuration
* [Quartz Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/quartzscheduler.md) - Quartz.NET scheduler configuration
* [AWS Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/awsscheduler.md) - AWS EventBridge Scheduler configuration
* [Azure Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/azurescheduler.md) - Azure Service Bus Scheduler configuration
* [InMemory Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/inmemoryscheduler.md) - InMemory scheduler for testing


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://brightercommand.gitbook.io/paramore-brighter-documentation/scheduler/switchingschedulers.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
