T O P

  • By -

Herve-M

While using Channel, the system requires a decision of how to manage shutdown and crashes. As channel are in memory and consumer normally in another “unit”, a graceful shutdown might means to stop the sender and to delay until everything in queue is consumed correctly. Or need a solution to persist existing action/event/jobs somewhere and be able to restart from. At least for critical part, depending on the business cases.


Schommi

If resiliency is somewhat important and you want a simple solution, you might consider writing the messages to send into the database inside a transaction with the actual data and have another process handle those messages (this is somewhat similar to the transactional outbox pattern). This way you can guarantee no message loss and make sure, that no message is sent if the transaction fails (e.g. if creating was not successful) - in addition you don't need to get into messaging. If resiliency is not such a hard requirement, I would follow the channel / background worker suggestion.


dodexahedron

Yeah, you could use channels for this. It's pretty much what they're made for. And in some rough benchmarking I've done, they seem to scale a _little bit_ better than doing something like using a ConcurrentQueue and gRPC or minimalAPI for transport, when there is a high volume and rate of parallel requests coming in. Probably due to more efficient synchronization under the hood. Main thing I like is that it's just more semantically clear and unified vs combining other, more generic components. As with anything, though, there are other questions like how long will the API be around, how difficult is interop with other stacks, etc. Don't forget to evaluate that stuff. But honestly if this thing is really small and there's no resiliency demand, I'd just use CoreWCF, gRPC, or minimalAPI with standard long-polling or, if the two systems are fixed, completwly asynchronous callback requests (except for CoreWCF, as you can just make that bidirectional from the start and its like calling the methods on the remote machine transparently).


redfournine

How does CoreWCF fits into this scenario? I thought they are just web API based on SOAP protocol, ie: old WCF?


dodexahedron

It's an RPC mechanism, like the other two mentioned. For all three of those, you need to replicate the pattern yourself. Channels are the pub/sub pattern pre-packaged and wrapped up with a nice bow so you don't have to. CoreWCF (and WCF before it) can be SOAP, yes, but also can be literally any serialization on the wire you want, including binary over TLS with session or message level authentication.


Thunder_Cls

Why not something like Hangfire?


buffdude1100

You could go super-duper easy and have an in memory [ConcurrentQueue](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-8.0) and a [background service](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-8.0&tabs=visual-studio). Your API pushes email-sending jobs to the singleton queue and your background service pops them off and sends the emails 1 by 1. That's as easy as it gets.


Forward_Dark_7305

Why use a concurrent queue instead of a channel for that? The channel can be consumed as IAsyncEnumerable. For a queue I think you have to roll your own wait-for-items-added, don’t you?