How is it different from hangfire?
Fast and observable background job processing for .NET
21–26 of 26 posts
Re: Fast and observable background job processing for .NET
#22How is it different from hangfire?
How is Hangfire different from the Azure DurableTask library?
- developer experience - hangfire simpler to use for simple scenarios (in many cases you can run an existing method in background with line of code)
- hangfire has some support for batches/delay/task dependency but DurableTask is way more full featured in my opinion
- hangfire has .net 4.8 framework support :(
Re: Fast and observable background job processing for .NET
#23Earlier quoted context omitted.
You have no control over concurrency/scheduling, have to manage scoping, error handling, etc. TPL/Threads add to much low level noise to the logic. Like you could easily blow up the thread pool depending on what you are doing, where a channel based implementation would just deal with spillover and not affect the other threads. You can easily capture scoped services that are disposed by the time the thread executes -…
> You have no control over concurrency/scheduling https://learn.microsoft.com/en-us/dotnet/api/system.threadin...
Re: Fast and observable background job processing for .NET
#24Earlier quoted context omitted.
It is a thin abstraction over Channels, and that’s by design. What it adds is graceful shutdown handling, OpenTelemetry integration, timeout support, and simple configuration. I kept needing those pieces in almost every project, so wrapping them up into a small reusable library felt worthwhile.
Out of curiosity, why do you use an explicit semaphore here? I usually used Parallel.ForEachAsync together with ReadAllAsync from the Channel. Avoiding the manual semaphore handling was one of the things I really liked about Channels.
Re: Fast and observable background job processing for .NET
#25Re: Fast and observable background job processing for .NET
#26Earlier quoted context omitted.
Out of curiosity, why do you use an explicit semaphore here? I usually used Parallel.ForEachAsync together with ReadAllAsync from the Channel. Avoiding the manual semaphore handling was one of the things I really liked about Channels.
I’m not entirely sure what the practical advantage of that approach would be compared to the explicit semaphore, but I’d be happy to learn more. If you think it’s a better solution, you’re more than welcome to open a pull request
Semaphores work well of course, as long as you don't make mistakes. Probably not an issue in your current version, but can easily happen if the code is more complex or especially when different developers later modify code like this. For example, you release the semaphore in a different class than the point where you acquire it, which makes this a bit less obvious than I'd like. If any developer later adds code that takes a different path this might break, and those kinds of bugs can be very annoying.
It's not really a problem with a simple case like this, but in general I don't use low-level concurrency primitives if there is a higher-level abstraction I can use that fits my problem.