Configuration Cheatsheet
Every EverTask configuration option at a glance: one row per option with its default. Details and examples live in the Configuration Reference; each section below links to the matching one.
Service Configuration
→ Reference: Service Configuration
| Method | Parameters | Default | Notes |
|---|---|---|---|
SetChannelOptions | int or BoundedChannelOptions | ProcessorCount × 200 (min 1000), FullMode=Wait | Max queued tasks + full behavior |
SetMaxDegreeOfParallelism | int | ProcessorCount × 2 (min 4) | Concurrent workers |
SetDefaultRetryPolicy | IRetryPolicy | LinearRetryPolicy(3, 500ms) | Global retry policy |
SetDefaultTimeout | TimeSpan? | null (no timeout) | Global per-attempt timeout |
SetDefaultAuditLevel | AuditLevel | Full | Audit trail verbosity (see table below) |
SetThrowIfUnableToPersist | bool | true | Throw on storage save failure |
UseShardedScheduler | int shardCount = 0 | Off (PeriodicTimerScheduler); auto-scale when 0 | High Schedule()-call rates (scheduling axis, not task-execution throughput) |
SetUseLazyHandlerResolution | bool | true (adaptive) | DisableLazyHandlerResolution() to opt out |
WithPersistentLogger | Action<PersistentLoggerOptions> | Disabled | Persists handler logs to DB; logs ALWAYS go to ILogger regardless |
SetRateLimiterOptions | Action<RateLimiterOptions> | See below | Keyed rate limiter global knobs (v3.7+) |
RegisterTasksFromAssembly | Assembly | n/a | Scan one assembly for handlers (required) |
RegisterTasksFromAssemblies | params Assembly[] | n/a | Scan multiple assemblies |
Audit / execution-log retention is not a builder method: register it with
services.AddAuditCleanup(policy, cleanupIntervalHours: 24)(IServiceCollection extension, EF Core storage package). Trims audits and execution logs (ExecutionLogRetentionDays/MaxExecutionLogsPerTask); any knob<= 0is treated as disabled. See Configuration Reference.
Rate Limiting (v3.7+)
→ Reference: Rate Limiting Configuration · Feature docs
Global knobs (SetRateLimiterOptions):
| Option | Default | Notes |
|---|---|---|
MaxParkedTasks | min(5000, 2 × default-queue channel capacity) | Distinct parked tasks before gated consumers pause (backpressure); ungated traffic keeps flowing |
MaxTrackedKeys | 100,000 | (task type, key) buckets before new keys fail OPEN |
MaxKeyLength | 256 | Longer keys hashed (SHA-256) |
EmitDeferralEvents | true | Deferral monitoring events, aggregated at source |
Per-handler policy (RateLimitPolicy property, new RateLimitPolicy(permits, period)):
| Property | Default | Notes |
|---|---|---|
Permits | n/a (ctor, required) | Public get-only; executions allowed per Period. Must be > 0 |
Period | n/a (ctor, required) | Public get-only; the window for Permits. Must be > 0 |
Burst | Permits | ≥ 1; 1 = strict even spacing |
ThrottleRetries | true | Retries re-acquire budget through the gate (never erodes the per-attempt timeout). Not an inline wait: a far slot re-parks the task and it fires via redelivery, restarting retry attempt numbering |
StartEmpty | false | false = new bucket starts full (burst available immediately); true = starts at steady rate (caps post-restart burst) |
MaxReservationHorizon | 1 hour | Farther slots → terminal rejection |
MaxInSlotWait | 1 second | No-op (binary-compat only): over-budget tasks always re-park to the scheduler; no inline consumer wait |
OverflowBehavior | WaitForCapacity | Discard rejects over-budget tasks: one-shot → Failed + OnError; recurring → occurrence skipped (series continues, no callback) |
Key source: task implements IRateLimitedTask, or handler overrides GetRateLimitKey(task). Null/empty key → task runs ungated (warning logged); if the key selector throws, it is caught, logged, and the task also runs ungated (fail-open).
Audit Levels
→ Reference: SetDefaultAuditLevel
| Level | StatusAudit | RunsAudit (recurring) | Use Case |
|---|---|---|---|
Full (default) | All status transitions | Every run | Critical tasks |
Minimal | Errors only | Every run (tracks last run) + LastExecutionUtc | High-frequency recurring |
ErrorsOnly | Errors only | Errors only (run with an exception recorded or status Failed) | Fire-and-forget |
None | Never | Never | Extremely high-frequency |
Minimal vs ErrorsOnly differ only in RunsAudit: Minimal records every recurring run (run-frequency history), ErrorsOnly only the runs that carry a non-empty exception string or end in status Failed. Decisions live in AuditPolicy.cs. Per-task override: dispatcher.Dispatch(task, auditLevel: AuditLevel.Minimal).
Audit Retention / Cleanup
→ Reference: Storage Configuration
Not a builder method; register on IServiceCollection (EF Core storage providers only): services.AddAuditCleanup(policy, cleanupIntervalHours: 24). Build the policy with a factory (AuditRetentionPolicy.WithUniformRetention(days) or WithErrorPriority(successDays, errorDays)) or set properties directly. Any knob <= 0 is treated as disabled.
AuditRetentionPolicy | Default | Notes |
|---|---|---|
StatusAuditRetentionDays | null (unlimited) | Days to keep StatusAudit rows |
RunsAuditRetentionDays | null | Days to keep RunsAudit rows |
ErrorAuditRetentionDays | null | Overrides the two above for error rows (keep errors longer) |
ExecutionLogRetentionDays | null | Days to keep TaskExecutionLog rows |
MaxExecutionLogsPerTask | null | Cross-run cap per task; oldest deleted first |
DeleteCompletedTasksAfterRetention | false | Hard-delete completed non-recurring tasks older than the longest configured audit window and with no remaining StatusAudit/RunsAudit rows. If a log-retention window/cap is active, a task that still owns execution logs is preserved (the purge only cascades once logs age out on their own). No audit window configured → nothing deleted. Recurring/Failed/Cancelled never auto-deleted. |
AddAuditCleanup / AuditCleanupOptions | Default | Notes |
|---|---|---|
RetentionPolicy | null | The policy supplied via the AddAuditCleanup(policy, …) arg; null = no cleanup runs |
cleanupIntervalHours arg → CleanupInterval | 24h | Sweep interval |
InitialDelay | 1 min | Delay before the first sweep |
Queue Configuration
→ Reference: Queue Configuration
Builder methods: ConfigureDefaultQueue(...), AddQueue(name, configure?), ConfigureRecurringQueue(...), EnsureRecurringQueue() (rarely needed: AddEverTask auto-creates the recurring queue). The builder also exposes .Services (the underlying IServiceCollection) so you can register your own singletons mid-chain (e.g. a custom IKeyedRateLimiter or IGuidGenerator). Note: if a custom/distributed IKeyedRateLimiter throws (e.g. Redis down), the gate fails open: the task runs unthrottled with a warning, never failing over a limiter outage. The well-known names are the constants QueueNames.Default ("default") and QueueNames.Recurring ("recurring").
Defaults differ between the auto-created default/recurring queues (inherit the global settings, QueueFullBehavior.Wait) and queues created via AddQueue (see Default column):
| Method | Parameters | Default for AddQueue queues | Notes |
|---|---|---|---|
SetMaxDegreeOfParallelism | int | 1 (sequential!) | default/recurring inherit the global value |
SetChannelCapacity | int | 500 | default/recurring inherit the global capacity |
SetChannelOptions | BoundedChannelOptions | n/a | Replaces the queue’s whole channel options (FullMode, SingleReader/Writer, …) |
SetFullBehavior | QueueFullBehavior | FallbackToDefault | Wait / FallbackToDefault / ThrowException, immediate dispatches only; the auto-created default queue uses Wait. FallbackToDefault = non-blocking try on target, then re-route to the default queue with blocking Wait backpressure (the task then runs on the default queue, so it does not honor the target queue’s parallelism/isolation; if the target is the default queue it degenerates to plain Wait) |
SetDefaultTimeout | TimeSpan? | unset → global | Chain: handler → queue → global (v3.7+) |
SetDefaultRetryPolicy | IRetryPolicy? | unset → global | Chain: handler → queue → global (v3.7+) |
The “Default for
AddQueuequeues” column above is whatAddQueueapplies. A rawnew QueueConfiguration()object (if you build one directly) defaults differently:Name = "default",MaxDegreeOfParallelism = 1, channel capacity2000withFullMode = Wait,QueueFullBehavior = FallbackToDefault. (Note the capacity differs fromAddQueue’s500.)
Storage
→ Reference: Storage Configuration
| Method | Package | Notes |
|---|---|---|
AddMemoryStorage() | core | Dev/test only: tasks lost on restart |
AddSqlServerStorage(cs, opt?) | EverTask.Storage.SqlServer | Options: SqlServerTaskStoreOptions; DbContext pooling + stored procedures |
AddPostgresStorage(cs, opt?) | EverTask.Storage.Postgres | Options: PostgresTaskStoreOptions; DbContext pooling + writable-CTE optimizations |
AddSqliteStorage(cs?, opt?) | EverTask.Storage.Sqlite | Options: SqliteTaskStoreOptions; cs defaults to "Data Source=EverTask.db" |
| Option (all EF Core store option types) | Default | Notes |
|---|---|---|
SchemaName | SQL Server: "EverTask"; PostgreSQL: "evertask"; SQLite: "" | PostgreSQL: lowercase only (null = public); SQL Server: null = dbo; SQLite: must stay "" (no schema concept) |
AutoApplyMigrations | true | Disable for manual migrations in production |
Logging
→ Reference: Logging Configuration
AddSerilog(opt => ...) (package EverTask.Logging.Serilog). Called with no argument, AddSerilog() defaults to a WriteTo.Console() sink.
WithPersistentLogger (PersistentLoggerOptions, v3.0+):
| Method | Default | Notes |
|---|---|---|
SetMinimumLevel(LogLevel) | Information | Min level persisted to DB (ILogger gets everything) |
SetMaxLogsPerTask(int?) | 1000 | null = unlimited (not recommended) |
Enable() / Disable() | enabled by WithPersistentLogger | Toggle DB persistence (logs still flow to ILogger when disabled) |
Monitoring
→ Reference: Monitoring Configuration
AddMonitoringApi(opt => ...) + app.MapEverTaskApi() (package EverTask.Monitor.Api). MapEverTaskApi accepts an optional Action<HttpConnectionDispatcherOptions> to tune the SignalR hub connection. Fixed paths: dashboard /evertask-monitoring, API /evertask-monitoring/api, SignalR hub /evertask-monitoring/hub. For setups without the EverTask builder there is services.AddEverTaskMonitoringApiStandalone(opt => ...) (you must register ITaskStorage yourself). It does not wire SignalR monitoring, and there is no IServiceCollection overload of AddSignalRMonitoring (it exists only on EverTaskServiceBuilder). MapEverTaskApi still maps the hub endpoint, but without the monitor subscription no live events are pushed; for live dashboard updates use the builder path (AddEverTask(...).AddMonitoringApi(...)).
| EverTaskApiOptions | Default | Notes |
|---|---|---|
EnableUI | true | Embedded React dashboard |
EnableSwagger | false | Separate Swagger document evertask-monitoring |
Username / Password | "admin" / "admin" | CHANGE IN PRODUCTION |
EnableAuthentication | true | JWT on API + hub |
JwtSecret | null (random 256-bit per instance) | Set explicitly (≥ 32 bytes) for multi-instance deployments |
JwtIssuer / JwtAudience | "EverTask.Monitor.Api" | n/a |
JwtExpirationHours | 8 | Token TTL |
EnableCors | true | ⚠ Only registers a named CORS policy (EverTaskMonitoringApi); EverTask does not apply it (no UseCors/RequireCors). To enforce CORS you must apply it yourself in your app pipeline |
CorsAllowedOrigins | [] (allow all) | Origins for the registered policy (used only when non-empty + the policy is actually applied). Restrict in production |
AllowedIpAddresses | [] (allow all) | IPv4/IPv6/CIDR; checked before auth |
MagicLinkToken | null (disabled) | Instant auth via /magic?token=... |
EventDebounceMs | 1000 | Dashboard SignalR refresh debounce |
BasePath | /evertask-monitoring | read-only computed; fixed |
ApiBasePath | /evertask-monitoring/api | read-only computed; fixed |
UIBasePath | /evertask-monitoring | read-only computed; fixed |
SignalRHubPath | /evertask-monitoring/hub | read-only computed; fixed |
AddSignalRMonitoring(...) (package EverTask.Monitor.AspnetCore.SignalR): 4 overloads: AddSignalRMonitoring(), (Action<SignalRMonitoringOptions>), (Action<HubOptions>), (Action<HubOptions>, Action<SignalRMonitoringOptions>). When used standalone (without AddMonitoringApi), you MUST also call app.MapEverTaskMonitorHub() after Build(): it maps the hub and subscribes the monitor, so without it no events are broadcast. Overloads: MapEverTaskMonitorHub() (default path), MapEverTaskMonitorHub("/custom"), MapEverTaskMonitorHub("/custom", hub => { ... }). Options:
| Option | Default | Notes |
|---|---|---|
IncludeExecutionLogs | false | Streams handler logs in events (bandwidth cost) |
Handler Properties
→ Reference: Handler Configuration
| Property / Member | Type | Default | Notes |
|---|---|---|---|
Timeout | TimeSpan? | Inherits queue/global | Per-attempt timeout |
RetryPolicy | IRetryPolicy? | Inherits queue/global | Per-handler retry |
QueueName | string? | "default" ("recurring" for recurring tasks) | Target queue. An unregistered/unknown name logs a warning and falls back to the default queue, both for routing and for the retry/timeout config resolution (the task runs on default with default’s config). |
RateLimitPolicy | RateLimitPolicy? | null (no limit) | Per-key throttling (v3.7+) |
GetRateLimitKey(task) | string? (override) | reads IRateLimitedTask.RateLimitKey | Derive the throttle key without changing the task type |
Obsolete:
CpuBoundOperation(bool) still exists on the handler but is[Obsolete]and has no effect: do not set it. For CPU-bound work, useTask.RuninsideHandle.
Dispatch Parameters
Optional parameters on every ITaskDispatcher.Dispatch(...) overload:
| Parameter | Type | Default | Notes |
|---|---|---|---|
auditLevel | AuditLevel? | null → global default (Full) | Per-dispatch audit override |
taskKey | string? | null (no dedup) | Idempotency key (≤ 200 chars). Non-recurring: InProgress (or an immediate one-shot whose delivery is already in flight) → no-op; Pending/Queued/WaitingQueue → update; terminal → replace. Recurring: InProgress → no-op; otherwise → update in place (never replaced), preserving NextRunUtc+CurrentRunCount only if NextRunUtc.HasValue (an exhausted series with no next run recalculates instead); recurring→one-shot re-dispatch is discarded |
cancellationToken | CancellationToken | default | Cancels the dispatch op (not execution) |
Recurring Schedule Builder
→ Reference: Recurring Tasks · used via Dispatch(task, Action<IRecurringTaskBuilder>, …). All times UTC.
| Stage | Methods |
|---|---|
| Start | Schedule() (recurring only) · RunNow() / RunDelayed(TimeSpan) / RunAt(DateTimeOffset) → .Then() |
| Interval | Every(n).Seconds()/.Minutes()/.Hours()/.Days()/.Weeks()/.Months() · EverySecond/Minute/Hour/Day/Week/Month() · OnHours() · OnDays(params DayOfWeek[]) · OnMonths(params int[]) |
| Refine | hour .AtMinute(0–59) · minute .AtSecond(0–59) · day .AtTime(TimeOnly) / .AtTimes(…) · week .OnDay(s) · month .OnDay(1–31) / .OnDays(…) / .OnFirst(DayOfWeek) |
| Cron | UseCron("expr") (5- or 6-field; overrides all other interval calls) |
| Limit | .RunUntil(DateTimeOffset) · .MaxRuns(int) (counts real runs; skipped-after-downtime don’t count) |
OnLast(DayOfWeek)does not exist (onlyOnFirst). Use a stabletaskKeyfor idempotent startup registration.
Retry Policy & Exception Filtering
LinearRetryPolicy(int retryCount, TimeSpan retryDelay) or LinearRetryPolicy(TimeSpan[] retryDelays). Default global policy: LinearRetryPolicy(3, 500ms), retrying everything except OperationCanceledException/TimeoutException. Fluent filtering (whitelist and blacklist cannot be mixed):
| Method | Mode | Notes |
|---|---|---|
.Handle<T>() / .Handle(params Type[]) | Whitelist | Retry only these types |
.DoNotHandle<T>() / .DoNotHandle(params Type[]) | Blacklist | Retry all except these |
.HandleWhen(Func<Exception,bool>) | Predicate | Highest priority |
.HandleTransientDatabaseErrors() | Preset | DbException (+ TimeoutException, blocked by the hardcoded guard) |
.HandleTransientNetworkErrors() | Preset | HttpRequestException, SocketException, WebException, TaskCanceledException (⚠ TaskCanceledException derives from OperationCanceledException, so it’s blocked by the hardcoded fail-fast guard and never actually retried) |
.HandleAllTransientErrors() | Preset | Both presets combined |
Performance Tuning
→ Reference: Performance Tuning Guidelines
| Workload | Max Parallelism | Channel Capacity | Notes |
|---|---|---|---|
| CPU-bound | ProcessorCount | Small (100–500) | Heavy computation |
| I/O-bound | ProcessorCount × 4 | Large (5000+) | API/DB/file operations |
| Mixed | Separate queues | Varies | Different configs per queue |
High Schedule() rate | ProcessorCount × 4+ | 10000+ | Sharded scheduler (scheduling axis only; execution stays storage-bound) |
See Also
- Full Configuration Reference: full detail for every option
- Keyed Rate Limiting: feature documentation
- Getting Started · Scalability · Resilience