EverTask 3.1.2
See the version list below for details.
dotnet add package EverTask --version 3.1.2
NuGet\Install-Package EverTask -Version 3.1.2
<PackageReference Include="EverTask" Version="3.1.2" />
<PackageVersion Include="EverTask" Version="3.1.2" />
<PackageReference Include="EverTask" />
paket add EverTask --version 3.1.2
#r "nuget: EverTask, 3.1.2"
#:package EverTask@3.1.2
#addin nuget:?package=EverTask&version=3.1.2
#tool nuget:?package=EverTask&version=3.1.2

Overview
EverTask is a high-performance .NET library for background task execution. It handles everything from simple fire-and-forget operations to complex recurring schedules, with persistence that survives application restarts.
If you've used MediatR, you'll feel right at home with the request/handler pattern. But unlike traditional in-memory task queues, EverTask persists tasks to storage, supports multi-queue workload isolation, and scales to extreme loads (>10k tasks/sec) when needed.
Works great with ASP.NET Core, Windows Services, or any .NET project that needs reliable background processing.
Key Features
- 🚀 Background Execution - Fire-and-forget, scheduled, and recurring tasks with elegant API
- 🎯 Multi-Queue Support (v1.6+) - Isolate workloads by priority, resource type, or business domain
- 🔑 Idempotent Task Registration (v1.6+) - Prevent duplicate recurring tasks with unique keys
- ⚡ High-Performance Scheduler (v2.0+) - PeriodicTimerScheduler with minimal lock contention and zero CPU when idle
- 🔥 Extreme Load Support (v2.0+) - Optional sharded scheduler for >10k tasks/sec scenarios
- 💾 Smart Persistence - Tasks resume after application restarts (SQL Server, SQLite, In-Memory)
- 🔄 Powerful Retry Policies - Built-in linear retry, custom policies, Polly integration
- ⏱️ Timeout Management - Global and per-task timeout configuration
- 📝 Task Execution Log Capture (v3.0+) - Proxy logger that always logs to ILogger with optional database persistence for audit trails
- 📊 Real-Time Monitoring - Local events + SignalR remote monitoring
- 🎨 Fluent Scheduling API - Intuitive recurring task configuration (every minute, hour, day, week, month, cron)
- 🔧 Extensible Architecture - Custom storage, retry policies, and schedulers
- 🏎️ Optimized Performance (v2.0+) - Reflection caching, lazy serialization, DbContext pooling
- 📈 Auto-Scaling Defaults (v2.0+) - Configuration that scales with your CPU cores
- 🔌 Serilog Integration - Detailed structured logging
- ✨ Async All The Way - Fully asynchronous for maximum scalability
Quick Start
Installation
dotnet add package EverTask
dotnet add package EverTask.SqlServer # Or EverTask.Sqlite
Configuration
using EverTask;
var builder = WebApplication.CreateBuilder(args);
// Register EverTask with SQL Server storage
builder.Services.AddEverTask(opt =>
{
opt.RegisterTasksFromAssembly(typeof(Program).Assembly);
})
.AddSqlServerStorage(
builder.Configuration.GetConnectionString("EverTaskDb")!,
opt =>
{
opt.SchemaName = "EverTask";
opt.AutoApplyMigrations = true;
});
var app = builder.Build();
app.Run();
Create Your First Task
Define a task request:
public record SendWelcomeEmailTask(string UserEmail, string UserName) : IEverTask;
Create a handler:
public class SendWelcomeEmailHandler : EverTaskHandler<SendWelcomeEmailTask>
{
private readonly IEmailService _emailService;
public SendWelcomeEmailHandler(IEmailService emailService)
{
_emailService = emailService;
}
public override async Task Handle(SendWelcomeEmailTask task, CancellationToken cancellationToken)
{
Logger.LogInformation("Sending welcome email to {Email}", task.UserEmail);
await _emailService.SendWelcomeEmailAsync(
task.UserEmail,
task.UserName,
cancellationToken);
}
}
Dispatch the task:
public class UserController : ControllerBase
{
private readonly ITaskDispatcher _dispatcher;
public UserController(ITaskDispatcher dispatcher) => _dispatcher = dispatcher;
[HttpPost("register")]
public async Task<IActionResult> RegisterUser(UserRegistrationDto dto)
{
// Create user...
// Send welcome email in background
await _dispatcher.Dispatch(new SendWelcomeEmailTask(dto.Email, dto.Name));
return Ok();
}
}
Documentation
📚 Full Documentation - Complete guides, tutorials, and API reference
Quick Links
- Getting Started - Installation, configuration, and your first task
- Task Creation - Requests, handlers, lifecycle hooks, and best practices
- Task Dispatching - Fire-and-forget, delayed, and scheduled tasks
- Recurring Tasks - Fluent scheduling API, cron expressions, idempotent registration
- Advanced Features - Multi-queue, sharded scheduler, continuations, cancellation
- Resilience & Error Handling - Retry policies, timeouts, CancellationToken usage
- Monitoring - Events, SignalR integration, custom monitoring
- Storage Configuration - SQL Server, SQLite, In-Memory, custom implementations
- Configuration Reference - Complete configuration documentation
- Configuration Cheatsheet - Quick reference for all config options
- Architecture & Internals - How EverTask works under the hood
Showcase: Powerful Features
Fluent Recurring Scheduler
Schedule recurring tasks with an intuitive, type-safe API:
// Run every day at 3 AM
await dispatcher.Dispatch(
new DailyCleanupTask(),
builder => builder.Schedule().EveryDay().AtTime(new TimeOnly(3, 0)));
// Run every Monday, Wednesday, Friday at 9 AM
var days = new[] { DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday };
await dispatcher.Dispatch(
new BackupTask(),
builder => builder.Schedule().EveryWeek().OnDays(days).AtTime(new TimeOnly(9, 0)));
// Run on the first day of every month
await dispatcher.Dispatch(
new MonthlyBillingTask(),
builder => builder.Schedule().EveryMonth().OnDay(1));
// Complex: Every 15 minutes during business hours, weekdays only
await dispatcher.Dispatch(
new HealthCheckTask(),
builder => builder.Schedule().UseCron("*/15 9-17 * * 1-5"));
// Limit executions: Run daily for 30 days, then stop
await dispatcher.Dispatch(
new TrialFeatureTask(userId),
builder => builder.Schedule()
.EveryDay()
.MaxRuns(30)
.RunUntil(DateTimeOffset.UtcNow.AddDays(30)));
Multi-Queue Workload Isolation
Keep critical tasks separate from heavy background work:
builder.Services.AddEverTask(opt =>
{
opt.RegisterTasksFromAssembly(typeof(Program).Assembly);
})
// High-priority queue for critical operations
.AddQueue("critical", q => q
.SetMaxDegreeOfParallelism(20)
.SetChannelCapacity(500)
.SetDefaultTimeout(TimeSpan.FromMinutes(2)))
// Background queue for CPU-intensive work
.AddQueue("background", q => q
.SetMaxDegreeOfParallelism(2)
.SetChannelCapacity(100))
// Email queue for bulk operations
.AddQueue("email", q => q
.SetMaxDegreeOfParallelism(10)
.SetChannelCapacity(10000)
.SetFullBehavior(QueueFullBehavior.FallbackToDefault))
.AddSqlServerStorage(connectionString);
Route tasks to queues:
public class PaymentProcessingHandler : EverTaskHandler<ProcessPaymentTask>
{
public override string? QueueName => "critical"; // High-priority queue
public override async Task Handle(ProcessPaymentTask task, CancellationToken cancellationToken)
{
// Critical payment processing
}
}
Smart Retry Policies with Exception Filtering
Control which exceptions trigger retries to fail-fast on permanent errors:
public class DatabaseTaskHandler : EverTaskHandler<DatabaseTask>
{
private readonly ILogger<DatabaseTaskHandler> _logger;
// Only retry transient database errors
public override IRetryPolicy? RetryPolicy => new LinearRetryPolicy(5, TimeSpan.FromSeconds(2))
.HandleTransientDatabaseErrors();
// Track retry attempts for monitoring
public override ValueTask OnRetry(Guid taskId, int attemptNumber, Exception exception, TimeSpan delay)
{
_logger.LogWarning(exception,
"Database task {TaskId} retry {Attempt} after {DelayMs}ms",
taskId, attemptNumber, delay.TotalMilliseconds);
return ValueTask.CompletedTask;
}
public override async Task Handle(DatabaseTask task, CancellationToken ct)
{
await _dbContext.ProcessAsync(task.Data, ct);
}
}
Exception Filtering Options:
// Whitelist: Only retry specific exceptions
RetryPolicy = new LinearRetryPolicy(3, TimeSpan.FromSeconds(1))
.Handle<DbException>()
.Handle<HttpRequestException>();
// Blacklist: Retry all except permanent errors
RetryPolicy = new LinearRetryPolicy(3, TimeSpan.FromSeconds(1))
.DoNotHandle<ArgumentException>()
.DoNotHandle<ValidationException>();
// Predicate: Custom logic (e.g., HTTP 5xx only)
RetryPolicy = new LinearRetryPolicy(3, TimeSpan.FromSeconds(1))
.HandleWhen(ex => ex is HttpRequestException httpEx && httpEx.StatusCode >= 500);
// Predefined sets for common scenarios
RetryPolicy = new LinearRetryPolicy(5, TimeSpan.FromSeconds(2))
.HandleAllTransientErrors(); // Database + Network errors
Idempotent Task Registration
Use unique keys to safely register recurring tasks at startup without creating duplicates:
// At application startup
public class RecurringTasksRegistrar : IHostedService
{
private readonly ITaskDispatcher _dispatcher;
public async Task StartAsync(CancellationToken ct)
{
// Register recurring tasks - safe to call on every startup
await _dispatcher.Dispatch(
new DailyCleanupTask(),
r => r.Schedule().EveryDay().AtTime(new TimeOnly(3, 0)),
taskKey: "daily-cleanup"); // Won't create duplicates
await _dispatcher.Dispatch(
new HealthCheckTask(),
r => r.Schedule().Every(5).Minutes(),
taskKey: "health-check");
await _dispatcher.Dispatch(
new WeeklySummaryTask(),
r => r.Schedule().EveryWeek().OnDay(DayOfWeek.Monday).AtTime(new TimeOnly(8, 0)),
taskKey: "weekly-summary");
}
public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}
builder.Services.AddHostedService<RecurringTasksRegistrar>();
Task Execution Log Capture
Capture all logs written during task execution and persist them to the database for debugging and auditing:
// Enable log capture in configuration
services.AddEverTask(cfg =>
{
cfg.RegisterTasksFromAssembly(typeof(Program).Assembly)
.WithPersistentLogger(log => log // Auto-enables persistence
.SetMinimumLevel(LogLevel.Information) // Filter log level
.SetMaxLogsPerTask(1000)); // Prevent unbounded growth
})
.AddSqlServerStorage(connectionString);
// Use the built-in Logger property in handlers
public class SendEmailHandler : EverTaskHandler<SendEmailTask>
{
public override async Task Handle(SendEmailTask task, CancellationToken ct)
{
Logger.LogInformation($"Sending email to {task.Recipient}");
try
{
await _emailService.SendAsync(task.Recipient, task.Subject, task.Body);
Logger.LogInformation("Email sent successfully");
}
catch (Exception ex)
{
Logger.LogError($"Failed to send email: {ex.Message}", ex);
throw;
}
}
}
// Retrieve logs via storage
var logs = await storage.GetExecutionLogsAsync(taskId);
foreach (var log in logs)
{
Console.WriteLine($"[{log.Level}] {log.Message}");
if (log.ExceptionDetails != null)
Console.WriteLine($"Exception: {log.ExceptionDetails}");
}
Performance Notes:
- Zero overhead when disabled - JIT optimizations eliminate all log capture code paths
- Minimal impact when enabled - ~5-10ms overhead for typical tasks
- Logs persist even on failure - Captured in the finally block for debugging failed tasks
What's New in v2.0
Version 2.0 is all about performance. We've optimized every hot path and made the defaults much smarter.
Scheduler Improvements
- PeriodicTimerScheduler is now the default, with minimal lock contention and using zero CPU when idle
- ShardedScheduler available for extreme loads—delivers 2-4x throughput when you're scheduling >10k tasks/sec
Storage Optimizations
- DbContext pooling makes storage operations 30-50% faster
- SQL Server now uses stored procedures, cutting status update roundtrips in half
Dispatcher Performance
- Reflection caching speeds up repeated task dispatching by 93% (~150μs → ~10μs)
- Lazy serialization eliminates unnecessary JSON conversion entirely
Worker Executor Enhancements
- Event data caching slashes monitoring serializations by 99% (60k-80k → ~10-20 per 10k tasks)
- Handler options caching eliminates 99% of runtime casts
- Parallel pending task processing makes startup 80% faster with 1000+ queued tasks
Auto-Scaling Configuration
No more manual tuning—defaults now scale with your CPU cores:
MaxDegreeOfParallelism:Environment.ProcessorCount * 2(previously hardcoded to 1)ChannelCapacity:Environment.ProcessorCount * 200(previously hardcoded to 500)
Better Developer Experience
- Configuration validation catches problems early with helpful warnings
- Zero-allocation patterns on .NET 7+
- Thread safety improvements and race condition fixes throughout
Quick Links
📦 NuGet Packages
- EverTask - Core library
- EverTask.SqlServer - SQL Server storage
- EverTask.Sqlite - SQLite storage
- EverTask.Serilog - Serilog integration
- EverTask.Monitor.AspnetCore.SignalR - Real-time monitoring
📝 Resources
- Changelog - Version history and release notes
- Attribution - Acknowledgements and license information
- GitHub Repository - Source code and issues
- Examples - Sample applications (ASP.NET Core, Console)
Roadmap
We have some exciting features in the pipeline:
- Web Dashboard: A simple web UI for monitoring and managing tasks
- WebAPI Endpoints: RESTful API for remote task management
- Additional Monitoring: Sentry Crons, Application Insights, OpenTelemetry support
- More Storage Options: PostgreSQL, MySQL, Redis, Cosmos DB
- Clustering: Multi-server task distribution with load balancing and failover
Contributing
Contributions are welcome! Bug reports, feature requests, and pull requests all help make EverTask better.
- Report issues: https://github.com/GiampaoloGabba/EverTask/issues
- Contribute code: https://github.com/GiampaoloGabba/EverTask/pulls
License
EverTask is licensed under the Apache License 2.0.
See ATTRIBUTION.md for acknowledgements and attributions.
Developed with ❤️ by Giampaolo Gabba
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Cronos (>= 0.11.1)
- EverTask.Abstractions (>= 3.1.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 7.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 7.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 7.0.0)
- Microsoft.Extensions.Logging (>= 7.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 7.0.1)
- Newtonsoft.Json (>= 13.0.4)
- UUIDNext (>= 4.2.1)
-
net7.0
- Cronos (>= 0.11.1)
- EverTask.Abstractions (>= 3.1.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 7.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 7.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 7.0.0)
- Microsoft.Extensions.Logging (>= 7.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 7.0.1)
- Newtonsoft.Json (>= 13.0.4)
- UUIDNext (>= 4.2.1)
-
net8.0
- Cronos (>= 0.11.1)
- EverTask.Abstractions (>= 3.1.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Newtonsoft.Json (>= 13.0.4)
- UUIDNext (>= 4.2.1)
-
net9.0
- Cronos (>= 0.11.1)
- EverTask.Abstractions (>= 3.1.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.10)
- Microsoft.Extensions.Hosting.Abstractions (>= 9.0.10)
- Microsoft.Extensions.Logging (>= 9.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.10)
- Newtonsoft.Json (>= 13.0.4)
- UUIDNext (>= 4.2.1)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on EverTask:
| Package | Downloads |
|---|---|
|
EverTask.Monitor.AspnetCore.SignalR
Easy background task with persistence for ASP.NET Core |
|
|
EverTask.Storage.EfCore
Easy background task with persistence for ASP.NET Core |
|
|
EverTask.Storage.SqlServer
Easy background task with persistence for ASP.NET Core |
|
|
EverTask.Logging.Serilog
Easy background task with persistence for ASP.NET Core |
|
|
EverTask.Storage.Sqlite
Easy background task with persistence for ASP.NET Core |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.0 | 0 | 11/4/2025 |
| 3.1.2 | 111 | 11/2/2025 |
| 3.1.1 | 111 | 11/1/2025 |
| 3.0.0 | 278 | 10/19/2025 |
| 2.0.0 | 276 | 10/19/2025 |
| 1.5.4 | 358 | 5/31/2024 |
| 1.5.3 | 312 | 5/23/2024 |
| 1.5.2 | 332 | 4/9/2024 |
| 1.5.1 | 558 | 11/23/2023 |
| 1.5.0 | 299 | 11/21/2023 |
| 1.4.1 | 308 | 11/19/2023 |
| 1.4.0 | 265 | 11/19/2023 |
| 1.3.0 | 284 | 11/19/2023 |
| 1.2.0 | 279 | 11/17/2023 |
| 1.1.0 | 256 | 11/16/2023 |
| 1.0.4-beta | 93 | 11/13/2023 |
| 1.0.3-beta | 88 | 11/13/2023 |
| 1.0.0 | 256 | 11/15/2023 |