Endatix.Modules.Jobs 0.7.6

dotnet add package Endatix.Modules.Jobs --version 0.7.6
                    
NuGet\Install-Package Endatix.Modules.Jobs -Version 0.7.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Endatix.Modules.Jobs" Version="0.7.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Endatix.Modules.Jobs" Version="0.7.6" />
                    
Directory.Packages.props
<PackageReference Include="Endatix.Modules.Jobs" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Endatix.Modules.Jobs --version 0.7.6
                    
#r "nuget: Endatix.Modules.Jobs, 0.7.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Endatix.Modules.Jobs@0.7.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Endatix.Modules.Jobs&version=0.7.6
                    
Install as a Cake Addin
#tool nuget:?package=Endatix.Modules.Jobs&version=0.7.6
                    
Install as a Cake Tool

Endatix.Modules.Jobs

Durable background job queue for long-running tenant operations.

Endatix Platform is an open-source data collection and management library for .NET. It is designed for building secure, scalable, and integrated form-centric applications that work with SurveyJS. Endatix empowers business users with advanced workflows, automation, and meaningful insights.

Installation:

dotnet add package Endatix.Modules.Jobs

For running and hosting the Endatix Platform, Endatix.Api.Host is the recommended main package as it simplifies the installation and setup process.

dotnet add package Endatix.Api.Host

The module is registered automatically by EndatixBuilder.UseDefaults() — no host code change is needed.

What it is

The BackgroundJobs table is the queue. Enqueueing is a single insert. Retry state — attempt count, next attempt time, and the terminal statuses — lives on the job row, so no second system can disagree with it about what a job is doing.

This package currently provides persistence and enqueueing only. It contains no runner and no sweeper, so enqueued jobs stay Pending until a host that executes jobs exists. The state machine, the handler contract, and the schema below describe the full design and are what execution will be built against.

Work that outlives a request belongs here: exporting a large submission set, delivering a webhook to one endpoint, backfilling or purging tenant data.

Module layout

Namespace Contents
Endatix.Core.Abstractions.BackgroundJobs IBackgroundJobQueue, IBackgroundJobHandler, BackgroundJobRequest, JobStatus — referenced by anything that enqueues or handles
Endatix.Modules.Jobs.Domain BackgroundJob entity and its state machine
Endatix.Modules.Jobs.Persistence jobs-schema contexts, EF configuration, migrations
Endatix.Modules.Jobs.Features BackgroundJobQueue

The abstractions live in Endatix.Core rather than here so that assemblies which cannot reference this module — Endatix.Infrastructure, most notably — can still enqueue.

Schema

Database schema: jobs

Table Purpose
BackgroundJobs One row per unit of work: type, payload, tenant, status, progress, retry state, result

The schema carries its own __EFMigrationsHistory, so job migrations advance independently of app-schema migrations.

Status

PendingProcessingCompleted | Failed | DeadLettered | Retrying | Canceled, and RetryingProcessing. A job cancelled before it is claimed never runs.

Status Meaning Terminal
Pending Enqueued, never started no
Processing Claimed by a runner; a heartbeat is expected no
Retrying An attempt failed retryably; waiting for its next attempt time no
Completed Success yes
Failed Deterministic failure — retrying cannot help yes
DeadLettered Retryable failure that exhausted its attempt budget yes
Canceled Cancelled by a user or by host shutdown yes

Failed and DeadLettered are separate because one status cannot express both "do not retry this" and "retried and gave up", and operators need to tell them apart.

Pending and Retrying both mean eligible to run at NextAttemptAt, so a single query dispatches either.

Enqueueing

var jobId = await backgroundJobQueue.EnqueueAsync(
    new BackgroundJobRequest("SubmissionExport", payloadJson, tenantId, userId),
    cancellationToken);

Use EnqueueManyAsync for fan-out — one job per webhook endpoint, say. The batch commits in a single transaction, so a partial fan-out cannot deliver to some destinations and silently drop the rest.

Enqueueing is not transactionally joined to app-schema writes: jobs live on their own DbContext, which cannot enlist in an AppDbContext transaction. To commit a domain change and a job together, raise a domain event and enqueue from the outbox handler — the outbox already guarantees the event survives the business transaction.

Writing a handler

Nothing executes handlers yet (see above), so an implementation registered today will not be invoked. The contract is documented here because it is what handlers will be held to, and because the obligations below are far cheaper to honour while a handler is being written than to retrofit.

Implement IBackgroundJobHandler and register it in DI. Routing is by JobType, and handlers may live in any assembly.

Four obligations, each invisible until it hurts in production:

  1. Return a failure Result for deterministic errors; throw only for transient ones. This is the only retry signal there is. Throwing on a permanent error re-runs expensive work until the attempt budget is gone.
  2. Scope every query to the job's TenantId explicitly. Outside a request the ambient tenant filter is permissive, not restrictive — a handler that queries as if it were in a request reads every tenant's data.
  3. Honour the CancellationToken, or the job cannot be cancelled or time-limited.
  4. Do not hold one DbContext for the length of the job. Open a scope per chunk via IServiceScopeFactory; a change tracker held for minutes accumulates every row streamed through it.

Registration

Registered via EndatixBuilder.UseDefaults()UseModule(JobsModule.Instance). The module implements IEndatixModule and IHasDbMigrations.

Gated by Endatix:FeatureFlags:JobsModule, off by default. The module owns a DbContext and its own migrations, so registering it where nothing enqueues would create a schema no code writes to.

The flag has to be turned on in the same release that moves webhook delivery onto the queue. Left off, upgrading hosts lose fan-out with no error to explain it.

Whether a given process executes jobs is a separate, configuration-level question — which is what allows API and worker roles to be deployed separately from the same image.

Migrations

PostgreSQL is currently the only supported provider. With the flag off — the default — nothing is registered and other providers are unaffected. With the flag on and a different provider configured, the host fails at startup naming the constraint, rather than deferring the failure to whichever call site enqueues first.

A second provider therefore has to exist by the time a feature depends on the queue.

Persistence is nonetheless provider-split: JobsPostgreSqlDbContext derives from JobsDbContextBase and owns its migrations and model snapshot under Persistence/Migrations/PostgreSql.

This is not stylistic. EF Core keeps one model snapshot per context type, so generating two providers' migrations against a single shared context makes the second generation overwrite the first's snapshot — after which the next migration for the first provider diffs against the wrong model and emits nonsense. Adding a provider therefore means adding a derived context, its own design-time factory, its own Config/<Provider>/ entity configuration and its own migrations folder — never reusing an existing one.

Run the commands from the repository root.

Always use Endatix.WebHost as the startup project. The design-time factories pin their own provider, so ConnectionStrings:DefaultConnection_DbProvider does not affect which migrations are generated — but a valid ConnectionStrings:DefaultConnection must be present.

PostgreSQL

dotnet ef migrations add <Name> \
  --startup-project src/Endatix.WebHost \
  --project src/Endatix.Modules.Jobs \
  --context JobsPostgreSqlDbContext \
  --output-dir Persistence/Migrations/PostgreSql

Migrations apply automatically at startup when Endatix:Data:EnableAutoMigrations is enabled.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Endatix.Modules.Jobs:

Package Downloads
Endatix.Hosting

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.6 136 9/9/2026