I really like Channels for in-memory queues like this, they're very nice and it's easy to make everything parallel. But if you need more than this you usually need persistence, and then you need something else entirely.
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.
Why do we need to serialize the jobs through a Channel<T>? Couldn't we just do Task.Run and let the runtime take care of scheduling our work?
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 - but you never catch it in dev because you get executed immediately and request takes long enough, etc.
Spawning threads will work but I can see the use in a small abstraction like this lib for sure. Not sure I would use a lib for this - would probably hand roll something since I don't like adding unvetted external deps by default.
https://learn.microsoft.com/en-us/dotnet/api/system.threadin...
BusyBee is focused on lightweight background processing. Everything is in‑memory, with no external storage required. It is designed for scenarios where you want to enqueue a task and have it executed immediately in the background, without scheduling or persistence.
A practical example: if you are building an API that accepts file uploads and you want to process the file asynchronously after the request returns, BusyBee is a good fit. You just enqueue the job and it runs in the background right away. If instead you need to schedule a nightly cleanup job or ensure jobs survive application restarts, Hangfire would be the better choice.
- 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 :(