DEV Community

Cover image for WJb vs Quartz vs Hangfire Benchmarks
Oleksandr Viktor
Oleksandr Viktor

Posted on

WJb vs Quartz vs Hangfire Benchmarks

WJb vs Quartz vs Hangfire Benchmarks

Performance comparison of WJb, Quartz.NET, and Hangfire for job enqueue operations.

Benchmark Environment

BenchmarkDotNet v0.15.8
.NET 10.0
Windows 11
Intel Core i7-12700K
20 Logical Cores
Enter fullscreen mode Exit fullscreen mode

Scenario

Each framework enqueues the same payload:

public sealed record EchoPayload(int Id, string Name);
Enter fullscreen mode Exit fullscreen mode

Validation tests are executed before benchmarking to verify that all frameworks successfully process the same workload and produce identical completion counts.

Job Enqueue Performance

JobCount WJb (baseline) Quartz Hangfire
1 22.6 µs / 1.3 KB 1.22× / 3.0× 17× / 17.6×
100 476 µs / 128 KB 2.5× / 4.0× 73× / 58.6×
1000 3.58 ms / 1.28 MB 3.3× / 3.6× 85× / 58.4×
10000 20.5 ms / 12.8 MB 5.5× / 8.5× 128× / 58.5×

Enqueue Throughput Chart

10,000 Jobs

WJb         20 ms  █
Quartz     113 ms  █████▌
Hangfire 2,613 ms  ████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
Enter fullscreen mode Exit fullscreen mode

Memory Consumption

10,000 Jobs

Framework Allocated Memory
WJb 12.81 MB
Quartz.NET 108.89 MB
Hangfire 749.68 MB

Memory Usage Chart

10,000 Jobs

WJb        12.8 MB  █
Quartz    108.9 MB  ████████▌
Hangfire  749.7 MB  ███████████████████████████████████████████████████████████
Enter fullscreen mode Exit fullscreen mode

Conclusion

For high-throughput job scheduling workloads, WJb demonstrates:

  • 5.5× higher enqueue throughput than Quartz.NET.
  • 128× higher enqueue throughput than Hangfire.
  • 8.5× lower memory consumption than Quartz.NET.
  • 58× lower memory consumption than Hangfire.

Resources

Top comments (1)

Collapse
 
arhancanli profile image
Arhan Canli •

Publishing the BenchmarkDotNet suite with a validation step that checks completion counts is good practice. Reading JobEnqueueBenchmarks.cs, though, the three enqueue benchmarks aren't measuring the same thing yet:

  • In GlobalSetup, Hangfire's BackgroundJobServer is started (WorkerCount = 1) and the Quartz scheduler is started too, so both are pulling and executing jobs on background threads while their enqueue loops are being timed. WJb's ExecuteLoopAsync only runs in GlobalCleanup, so WJb is measured on enqueue alone. Part of the 128x and 5.5x is the other two doing execution work concurrently, competing for the same cores and allocating for it.
  • The stores live in GlobalSetup and are never cleared between iterations, so each later iteration enqueues into a store that already holds every earlier iteration's jobs. That penalises whichever framework's insert cost grows with store size.
  • Hangfire's Enqueue serialises the method call expression and arguments to JSON, because with a persistent storage the job has to survive a process restart; it still pays that cost with MemoryStorage. That's a guarantee an in-memory queue doesn't aim for, so it's worth stating which guarantees each framework provides next to the numbers.

Starting no workers in any framework during the enqueue benchmark (or starting them in all three), and clearing the stores in IterationSetup, would make the enqueue column an apples-to-apples comparison. The JobExecuteBenchmarks file would then be the place for end-to-end throughput.