Background jobs
Work that does not belong in a request runs on scheduled jobs. Job state is persisted in the database, so a restart does not lose scheduled work.
The dashboard is at Hangfire:DashboardPath (/hangfire by default) and is restricted to
administrators.
The jobs
Section titled “The jobs”All configured under the BackgroundJobs section. Each block has at least Enabled, Interval,
and MaxItems.
| Job | Does | Interval | Batch |
|---|---|---|---|
PermissionRebuild |
Materialises effective permissions from the rebuild queue. | 30 s | 200 |
ReminderDispatch |
Fires due document reminders. | 1 min | 200 |
EmailDelivery |
Drains the outbound email outbox. | 1 min | 100 |
SignatureExpiry |
Expires stale signature requests. | 5 min | 200 |
FolderEmailIntake |
Polls a mailbox and files attachments. Disabled by default. | 5 min | - |
UploadSessionSweep |
Cleans up abandoned chunked uploads. | 15 min | 200 |
WorkflowEscalation |
Escalates overdue workflow tasks. | 15 min | 200 |
PreviewGeneration |
Renders missing previews and thumbnails. | 15 min | 200 |
OcrBackfill |
Extracts text from documents that have none. | 15 min | 100 |
RetentionCleanup |
Purges recycle-bin items past retention. | 1 h | 200 |
OrphanByteReclamation |
Deletes blobs nothing references any more. | 6 h | 200 |
StorageIntegrity |
Re-hashes stored blobs and verifies them. | 12 h | 500 |
A WorkflowAssignmentReconciliation job also runs, reassigning tasks belonging to departed users.
Job-specific settings
Section titled “Job-specific settings”| Job | Extra settings |
|---|---|
UploadSessionSweep |
SessionLifetime (1 day) - how long an abandoned session survives. |
OrphanByteReclamation |
MinimumAge (1 hour) - how long a blob must be unreferenced before deletion. |
WorkflowEscalation |
EscalationWindow (2 days) - how long a task may sit before escalation. |
PreviewGeneration |
MaxAttempts (3) - retries before giving up on a version. |
EmailDelivery |
MaxAttempts (3), BaseBackoff (1 min), LeaseTimeout (5 min). |
Reading the cadences
Section titled “Reading the cadences”The intervals are not arbitrary, and the pattern is worth understanding before changing any of them.
Fast (30 s - 1 min) for things a user is waiting on. Permission rebuild, reminders, email.
Medium (5 - 15 min) for things that should happen soon but that nobody is watching. Previews, text extraction, escalation, session cleanup. A new document without a thumbnail for a few minutes is acceptable; the alternative is doing that work inside the upload request.
Slow (1 - 12 h) for housekeeping. Retention, byte reclamation, integrity verification. These scan and are deliberately infrequent.
Cadence is a real cost
Section titled “Cadence is a real cost”The configuration file itself records why PermissionRebuild runs every 30 seconds rather than
every 5: access-control writes drain the rebuild queue inline, in the same transaction, so
this job is a safety net for rows that outlive their request, not the primary path. At a
5-second cadence the job runner’s own bookkeeping became the dominant cost of an otherwise idle
system.
That is the general lesson. A job that ticks frequently and usually finds nothing to do is not free - it costs a scheduler wake-up, a connection, and a query, on every tick, forever.
Two-stage deletion
Section titled “Two-stage deletion”Deleting a document does not free disk space, and the reason is two jobs with different jobs to do:
RetentionCleanuppurges the document record once it is past retention.OrphanByteReclamationlater deletes the underlying blob, if nothing else references it and it is older thanMinimumAge.
Because storage is content-addressed, a blob may still be referenced by other documents. Space is therefore freed some hours after a purge, not at it. See Governance and retention.
Enabling and disabling
Section titled “Enabling and disabling”Every job can be turned off with its Enabled flag. Two are worth knowing about:
FolderEmailIntakeis disabled by default and needs both its own flag andEmailIntake:Enabledto be turned on.- Disabling
PermissionRebuildis usually safe in the short term, because access-control writes drain the queue inline. It is a safety net, not the primary path - but leaving it off indefinitely means nothing catches the rows that outlive their request.
Disabling StorageIntegrity removes your only automatic detection of blob corruption or missing
files. Leave it on.
Monitoring
Section titled “Monitoring”The dashboard shows scheduled, running, succeeded, and failed jobs, with retry history.
Hangfire:RetryAttempts (3 by default) controls automatic retries.
A job failing consistently is worth investigating rather than waiting out - a preview job failing every pass usually means the converter path is wrong, not that the documents are unusual.
Related
Section titled “Related”- Configuration keys - the full
BackgroundJobssection. - Performance and tuning - job load in context.
- Deployment - the startup check.
- Troubleshooting - symptoms that trace back to a job not running.