Wojciech Wentland
projects / corfedo-work
status
alpha
license
Apache-2.0
stack
.NET 10, PostgreSQL
source
corfedo/corfedo-work

Corfedo Work

Background work for .NET that lives in your database and commits in your transactions.

You request work in the same transaction as the change that needs it, so a rollback leaves nothing behind. There is no broker, no scheduler process and no second database. PostgreSQL is supported today.

await using var transaction = await connection.BeginTransactionAsync(ct);
// INSERT INTO users ...
await jobs.RequestAsync(transaction, Jobs.Welcome, new WelcomeArgs(42), cancellationToken: ct);
await transaction.CommitAsync(ct);   // no commit, no job

How it works

  • A row with a lease. A worker claims a due row and holds it for a short lease, renewed while it runs. If the worker dies, the lease expires and another replica picks the row up. No cleanup job resets stuck work.
  • A fence on every write. Each claim gets a new fence number. A worker that lost its lease can no longer commit, even if it keeps running.
  • A wake-up at commit. When a transaction that makes work due commits, the processes that run it are notified. Polling stays as a slow fallback.

Jobs, cron schedules, leases on your own tables, reconciliation and signals are built on those three. Each works alone: signals need no framework tables, and leases need no jobs.

The problems it is for

  • A job ran before the row it needed was committed, or a rollback left the job behind.
  • A killed pod left a job “processing” until someone reset it.
  • A worker whose lock had expired kept writing after another worker took over.
  • Two replicas both ran the nightly cron job.
  • One tenant’s backlog starved every other tenant.
  • A status column in your table drifted from the job framework’s own state.

What it is not

  • Not exactly-once. Work runs at least once. Fencing protects writes to the same database; an email or an HTTP call cannot be taken back, so handlers deduplicate them with the run’s stable execution ID.
  • Not a message bus, and not a workflow engine that replays code.
  • No dashboard. Status, history and incidents are APIs and OpenTelemetry signals.

Status

Alpha: the API can still change. Install it from NuGet with dotnet add package Corfedo.Work.PostgreSql. The core and the PostgreSQL store are trimming and Native AOT compatible. Coming from Hangfire, Quartz.NET or TickerQ? The repository on GitHub has a migration guide for each, along with the getting-started guide and the design documents.

writing about Corfedo Work
11

LISTEN/NOTIFY performance in PostgreSQL

A NOTIFY in the transaction capped PostgreSQL 18.6 and 19 RC1 at about 3,900 commits per second, with 8 clients or 64. Sending notifications in batches after commit brought 64 clients back to 50,000.

measurement 2026-11-04 · 9 min