Throughput and benchmarks
Throughput
Section titled “Throughput”On a Hetzner Cloud CX33 (cost-optimized, 4 shared vCPUs, AMD EPYC Rome, 8 GB of RAM), with PostgreSQL 16 in a container on the same
machine (its default settings, so every commit waits for the disk), .NET 10 and EF Core 10, XactJobs drained a backlog of 20,000 no-op
jobs at 2,300 to 2,600 jobs per second. The best setting was 2 workers, MaxDegreeOfParallelism 4 and WithBatchSize(100).
Each job is still its own transaction: its changes, the delete of its row and its history row commit together.
With real jobs, their own work sets the pace. A larger batch saves claims, which helps short jobs, at a cost for slow ones: see Batch size.
Benchmarks
Section titled “Benchmarks”The benchmarks are in src/XactJobs.Benchmarks, to measure on your own machine. They measure XactJobs’ own code, to catch regressions between commits: compare two commits on the same machine, one run at a time, with nothing else running. Always build in Release.
dotnet build -c Release src/XactJobs.Benchmarks/XactJobs.Benchmarks.csprojmicro: without a database
Section titled “micro: without a database”BenchmarkDotNet, with the allocations per call: enqueueing (the expression tree, evaluating the arguments and serializing them), running a job (reading the arguments, finding the compiled delegate and calling it), the next run of a periodic job, and the save check.
dotnet run --no-build -c Release -f net10.0 --project src/XactJobs.Benchmarks -- micro --filter "*"drain: a backlog of no-op jobs
Section titled “drain: a backlog of no-op jobs”Drains a backlog of jobs that do nothing, with XactJobs and with plain EF doing the least database work for the same result (the same claim, then for each job its delete and its history row, saved together). The difference per job is XactJobs’ own cost. It runs on SQLite in memory by default, or on a PostgreSQL or SQL Server server:
dotnet run --no-build -c Release -f net10.0 --project src/XactJobs.Benchmarks -- drain --jobs 3000 --runs 5
dotnet run --no-build -c Release -f net10.0 --project src/XactJobs.Benchmarks -- drain --jobs 10000 --runs 3 --workers 2 --parallelism 4 \ --batch-size 100 --postgres "Host=127.0.0.1;Port=55432;Username=postgres;Password=bench;Database=postgres"--sqlserver <connection string> runs it on SQL Server. Each drain gets a new database on that server, with the schema from the install
script, dropped afterwards. The benchmark README has all the
options, and how to start the database in a container.