> 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/brighterschedulersupport/tickerqscheduler.md).

# TickerQ

TickerQ is a high-performance, reflection-free background task scheduler for .NET that uses source generators.

> **Reference** · Applies to **Brighter V10**

[TickerQ](https://github.com/Arcenox-co/TickerQ) is a high-performance, reflection-free background task scheduler for .NET that uses source generators. Brighter provides integration with TickerQ for [scheduler functionality](/paramore-brighter-documentation/scheduler/brighterschedulersupport.md), offering a modern, lightweight alternative for distributed scheduling.

## TickerQ Overview

TickerQ is designed for performance and cloud-native environments. Unlike traditional schedulers, it leverages .NET source generators to avoid runtime reflection, making it extremely fast and memory-efficient. Key features include:

* **Reflection-Free**: Uses source generators for compile-time job discovery
* **High Performance**: Minimal memory footprint and fast startup
* **Dashboard**: Built-in real-time dashboard for monitoring jobs
* **Persistence**: Support for Entity Framework Core
* **Flexible Scheduling**: Cron expressions and time-based scheduling
* **Clean API**: Modern, type-safe API design

For more information, visit the [TickerQ website](https://tickerq.net/).

## How Brighter Integrates with TickerQ

Brighter integrates with TickerQ through:

1. **TickerQBrighterJob**: A specialized job that executes scheduled Brighter messages
2. **TickerQSchedulerFactory**: Factory that creates Brighter's message scheduler backed by TickerQ
3. **TickerQScheduler**: Scheduler that schedules Brighter messages using TickerQ

When you schedule a message with Brighter:

1. Brighter uses the TickerQ manager to schedule a job
2. TickerQ persists the job (if configured)
3. At the scheduled time, TickerQ triggers the execution
4. The `TickerQBrighterJob` dispatches the message via Brighter's Command Processor

## TickerQ NuGet Packages

Install the required NuGet packages:

```bash
dotnet add package Paramore.Brighter.MessageScheduler.TickerQ
dotnet add package TickerQ
```

For persistence, add the EF Core package:

```bash
dotnet add package TickerQ.EntityFrameworkCore
```

## TickerQ Configuration

### TickerQ Scheduler Factory Options

`TickerQSchedulerFactory` is the one scheduler factory with **no settable properties at all**. Its whole surface is three required constructor arguments, and a reader cannot construct it without all three; the two properties it does expose, `GetOrCreateSchedulerId` and `ParseSchedulerId`, are get-only and cannot be replaced.

| Option                      | Type                                                             | Default | Description                                                                    |
| --------------------------- | ---------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------ |
| `timeTickerManager`         | `ITimeTickerManager<TimeTickerEntity>`                           | `none`  | Adds, updates and deletes the time tickers Brighter schedules messages with.   |
| `tickerPersistenceProvider` | `ITickerPersistenceProvider<TimeTickerEntity, CronTickerEntity>` | `none`  | Reads a ticker back by its identifier when a scheduled message is rescheduled. |
| `timeProvider`              | `TimeProvider`                                                   | `none`  | The clock the scheduler measures delays against.                               |

All three come out of the container, which is why every example below builds the factory from a `provider` rather than with `new`. Everything else about TickerQ — persistence, the dashboard, the poll interval — is configured on TickerQ itself through `AddTickerQ`.

### Basic Configuration

Configure Brighter with TickerQ scheduler in your `Program.cs`:

```csharp
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessageScheduler.TickerQ;
using TickerQ.DependencyInjection;
using TickerQ.Utilities.Entities;
using TickerQ.Utilities.Interfaces;
using TickerQ.Utilities.Interfaces.Managers;

var builder = WebApplication.CreateBuilder(args);

// Configure TickerQ
builder.Services.AddTickerQ();

// Configure Brighter with TickerQ scheduler
builder.Services.AddBrighter(options =>
{
    options.HandlerLifetime = ServiceLifetime.Scoped;
})
.UseScheduler(provider =>
{
    var timeTickerManager = provider.GetRequiredService<ITimeTickerManager<TimeTickerEntity>>();
    var persistenceProvider = provider.GetRequiredService<ITickerPersistenceProvider<TimeTickerEntity, CronTickerEntity>>();
    var timeprovider = provider.GetRequiredService<TimeProvider>();
    return new TickerQSchedulerFactory(timeTickerManager, persistenceProvider, timeprovider);
});

var app = builder.Build();

app.UseTickerQ();
```

### Configuration with Persistence (EF Core)

For production scenarios, you should use persistent storage to ensure jobs are not lost during restarts:

```csharp
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using TickerQ.DependencyInjection;
using TickerQ.EntityFrameworkCore.DbContextFactory;
using TickerQ.EntityFrameworkCore.DependencyInjection;

builder.Services.AddTickerQ(options =>
{
    options.AddOperationalStore(efOptions =>
    {
        efOptions.UseTickerQDbContext<TickerQDbContext>(dbOptions =>
        {
            dbOptions.UseSqlite(
                "Data Source=tickerq-brighter-sample.db",
                b => b.MigrationsAssembly(typeof(Program).Assembly));
        });
    });
});

var app = builder.Build();

// you must migrate the database
using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<TickerQDbContext>();
    db.Database.Migrate();
}
app.UseTickerQ();
```

For more information, see TickerQ's [Entity Framework Core](https://tickerq.net/features/entity-framework.html) documentation.

### Enabling the Dashboard

TickerQ comes with a built-in dashboard for monitoring scheduled jobs:

```bash
dotnet add package TickerQ.Dashboard
```

```csharp
using TickerQ.Dashboard.DependencyInjection;
using TickerQ.DependencyInjection;

builder.Services.AddTickerQ(options =>
{
    options.AddDashboard(o =>
    {
        o.SetBasePath("/dashboard"); //to configure the dashboard path
    });
});
```

You can then access the dashboard at `{{appurl}}/dashboard`.

## TickerQ Code Examples

### Basic Scheduling

Scheduling a message with TickerQ execution is identical to other schedulers in Brighter, as the `IAmACommandProcessor` interface abstracts the underlying implementation.

```csharp
using System;
using System.Threading.Tasks;
using Paramore.Brighter;

public class NotificationService
{
    private readonly IAmACommandProcessor _commandProcessor;

    public async Task ScheduleNotification(string userId)
    {
        // Schedule a reminder for 24 hours later
        var reminderCommand = new SendReminderCommand { UserId = userId };
        
        var schedulerId = await _commandProcessor.SendAsync(
            TimeSpan.FromHours(24),
            reminderCommand
        );

        Console.WriteLine($"Scheduled reminder with ID: {schedulerId}");
    }
}
```

### Cancelling a Scheduled Job

You can cancel a scheduled job using the ID returned during scheduling:

```csharp
using System.Threading.Tasks;
using Paramore.Brighter;

// ... inside your own class; _scheduler is injected
public async Task CancelNotification(string schedulerId)
{
    // Cancel the specific job using the scheduler interface
    // Note: You typically need the IAmAMessageSchedulerAsync interface here
    await _scheduler.CancelAsync(schedulerId);
}
```

### Rescheduling a Scheduled Job

You can reschedule a scheduled job using the ID returned during scheduling:

```csharp
using System;
using System.Threading.Tasks;
using Paramore.Brighter;

// ... inside your own class; _scheduler is injected
public async Task RescheduleNotification(string schedulerId, DateTimeOffset at)
{
    // Reschedule the specific job using the scheduler interface
    // Note: You typically need the IAmAMessageSchedulerAsync interface here
    // Note: You can't reschedule a job that has already been executed or  in progress
    await _scheduler.ReSchedulerAsync(schedulerId, at);
}
```

## TickerQ Best Practices

### 1. Use Persistence in Production

Always configure TickerQ with a persistent store (like EF Core) for production environments. In-memory scheduling is suitable only for development or non-critical transient tasks.

### 2. Monitor via Dashboard

Leverage the TickerQ dashboard to inspect job states, failures, and upcoming schedules. This is invaluable for debugging and operations.

## TickerQ Troubleshooting

### Jobs Not Firing

* **Check Host**: TickerQ runs as a hosted service. Ensure TickerQ service started is called and the host is kept alive.

```csharp
using TickerQ.DependencyInjection;

app.UseTickerQ();
```

* **Timezone**: Be aware of timezone settings when scheduling absolute times. Brighter typically uses UTC.

```csharp
using System;
using TickerQ.DependencyInjection;

builder.Services.AddTickerQ(options =>
{
    options.ConfigureScheduler(c =>
    {
        c.SchedulerTimeZone = TimeZoneInfo.Utc;
    });
});
```

### Dashboard Not Loading

* Verify `app.UseTickerQDashboard()` is called in the pipeline.
* Check if the configured path (default `/tickerq/dashboard`) conflicts with other routes.

## Related Documentation

* [Brighter Scheduler Support](/paramore-brighter-documentation/scheduler/brighterschedulersupport.md) - Overview of scheduling in Brighter
* [InMemory Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/inmemoryscheduler.md) - Lightweight scheduler for testing
* [Hangfire Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/hangfirescheduler.md) - Alternative production scheduler with dashboard
* [AWS Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/awsscheduler.md) - Cloud-native AWS scheduling
* [Azure Scheduler](/paramore-brighter-documentation/scheduler/brighterschedulersupport/azurescheduler.md) - Cloud-native Azure scheduling
* [TickerQ Documentation](https://tickerq.net) - Official

## TickerQ Summary

TickerQ integration for Brighter offers a modern, high-performance scheduling option.

* **Fast**: Source-generator based, low overhead.
* **Visual**: Integrated dashboard.
* **Standard**: Fully implements Brighter's `IAmAMessageSchedulerSync` and `IAmAMessageSchedulerAsync` interfaces.

Use TickerQ when you want a lightweight, modern scheduler without the legacy footprint of older libraries.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
