Appearance
GrydJobs Module
GrydJobs is a provider-agnostic background job processing framework for .NET applications. It provides clean abstractions for fire-and-forget, delayed, recurring, and continuation jobs with built-in retry, dead letter queue, multi-tenancy, and observability.
✨ Features
| Feature | Description |
|---|---|
| 🔥 Fire-and-Forget | Enqueue jobs for immediate background execution |
| ⏰ Delayed Jobs | Schedule jobs for future execution |
| 🔄 Recurring Jobs | Cron-based scheduling with auto-discovery |
| 🔗 Continuation Jobs | Chain jobs to run after parent completes |
| 🔁 Retry Policies | Configurable per-job retry with Polly |
| 💀 Dead Letter Queue | Failed jobs preserved for inspection and retry |
| 🏢 Multi-Tenancy | Automatic tenant isolation across all operations |
| 📊 Observability | Metrics, traces, and health checks |
| 🎛️ Dashboard | Embedded Hangfire dashboard with auth |
| 🔌 Provider-Agnostic | Swap Hangfire for Quartz.NET without code changes |
📦 Packages
GrydJobs is modular — use only what you need:
📦 GrydJobs # Meta-package (includes all)
├── GrydJobs.Core # Abstractions, entities, DTOs
├── GrydJobs.Application # CQRS handlers, validators, MediatR
├── GrydJobs.Infrastructure # EF Core persistence, Hangfire provider, Polly
└── GrydJobs.API # REST controllers, health checks, dashboard🚀 Quick Start
1. Install the meta-package
bash
dotnet add package GrydJobs2. Register services
csharp
builder.Services.AddGrydJobs(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("Jobs")!;
options.Queues = ["default", "critical", "low"];
options.WorkerCount = 10;
options.AutoRegisterRecurringJobs = true;
options.JobAssemblies = [typeof(MyJob).Assembly];
});
// Optional: health checks
builder.Services.AddGrydJobsHealthChecks();3. Configure middleware
csharp
app.UseGrydJobs();
app.UseGrydJobsDashboard(); // Available at /grydjobs/dashboard
if (app.Environment.IsDevelopment())
{
await app.ApplyGrydJobsMigrationsAsync();
}4. Create your first job
csharp
public class SendEmailJob : IJob<SendEmailArgs>
{
private readonly IEmailSender _sender;
public SendEmailJob(IEmailSender sender) => _sender = sender;
public async Task ExecuteAsync(
SendEmailArgs args,
JobExecutionContext context,
CancellationToken ct)
{
await _sender.SendAsync(args.To, args.Subject, args.Body, ct);
}
}
public record SendEmailArgs(string To, string Subject, string Body);5. Enqueue from anywhere
csharp
// Via DI
public class OrderService
{
private readonly IJobScheduler _scheduler;
public async Task PlaceOrderAsync(Order order)
{
// Fire-and-forget
await _scheduler.EnqueueAsync<SendEmailJob, SendEmailArgs>(
new SendEmailArgs(order.Email, "Order Confirmed", $"Order #{order.Id}"));
// Delayed (30 minutes)
await _scheduler.ScheduleAsync<SendEmailJob, SendEmailArgs>(
new SendEmailArgs(order.Email, "Feedback", "How was your order?"),
TimeSpan.FromMinutes(30));
}
}📖 Documentation
| Section | Description |
|---|---|
| Getting Started | Installation, configuration, first job |
| Job Types | Fire-and-forget, delayed, recurring, continuation |
| Configuration | Options, queues, retry policies |
| Retry & Dead Letter Queue | Retry policies, DLQ inspection, purge |
| Multi-Tenancy | Tenant isolation, context propagation |
| API Reference | REST endpoints, request/response schemas |
| Dashboard | Embedded monitoring UI |
| Providers | Hangfire configuration, Quartz.NET (future) |
| Advanced | Filters, idempotency, testing, observability |
🏗️ Architecture
┌──────────────────────────────────────────────────────┐
│ GrydJobs.API │
│ Controllers • Health Checks • Dashboard Middleware │
├──────────────────────────────────────────────────────┤
│ GrydJobs.Application │
│ CQRS Commands/Queries • Validators • MediatR │
├──────────────────────────────────────────────────────┤
│ GrydJobs.Infrastructure │
│ EF Core Repositories • Hangfire Provider • Polly │
├──────────────────────────────────────────────────────┤
│ GrydJobs.Core │
│ Interfaces • Entities • DTOs • Enums • Config │
└──────────────────────────────────────────────────────┘