StephenCleary / AsyncEx

A helper library for async/await.
MIT License
3.49k stars 358 forks source link

Dedicated Threadpool context with AsyncContext. #248

Closed oliver021 closed 2 years ago

oliver021 commented 2 years ago

Hi, I want to use this library to make a dedicated thread pool, I thought that AsyncContext can help me with it. Would that be a good option or should I think of something else? Thanks in advance.

oliver021 commented 2 years ago

A necessary clarification: My main reason for wanting a dedicated threadpool, is to not get in the way of the native Threadpool in ASP.NET applications.

StephenCleary commented 2 years ago

AsyncContext is probably not going to be what you want. It provides a single-threaded context, where any asynchronous continuations are scheduled back to that single thread. There's no way to make it multi-threaded. AsyncEx doesn't provide anything like a custom thread pool and I have no plans to add one.

As a more general observation, this is a very unusual request. If the ASP.NET requests need to wait for the other thread pool, then you may as well use the ASP.NET thread pool. If the ASP.NET requests do not need to wait, then you should be using a basic distributed architecture, which is best implemented with a completely separate background process, and in that case (of course) there would be no interference with the ASP.NET thread pool. I'm having a hard time thinking of a situation where it would make sense to have another thread pool within the same ASP.NET process.

oliver021 commented 2 years ago

Thanks Stephen. Yes, it's unusual but for example Hangfire uses dedicated ThreadPool for perfomance jobs. I'll do something similar and I was wondering if this library offers any of this. In fact, they implement their own TaskScheduler as well in Quartz, but I'd like to know what you think about this idea. Thanks again.

StephenCleary commented 2 years ago

I generally recommend a distributed architecture. Hangfire is a somewhat decent all-in-one solution but has some sharp corners as I discuss here. Specifically:

  1. It requires an ACID db server instead of a scalable queue. You either have to add a db server, or add the message queueing load to an existing db server.
  2. Message serialization is not specified. As recently as 2019 Hangfire just didn't support rolling upgrades at all. Currently they do but only if your job signature doesn't change; so it's still pretty fragile when it comes to future updates.
  3. You'll need to set up notifications for failed jobs, since Hangfire doesn't have poison queues.

To summarize, Hangfire is a decent solution to push something out quickly, but I have concerns with long-term maintenance.

AsyncEx doesn't have anything built-in to handle scheduling. If I need Cron jobs I either use Azure Functions or run them myself in a background service scheduled with Cronos (developed by the Hangfire team). But I always run them in a separate application (and on a separate server) from my ASP.NET apps.

oliver021 commented 2 years ago

Yes, I agree with you about Hangfire. Although technically it is not to compete, I am trying to make my own implementation, precisely with support for brokers such as Kafka or RabbitMQ and providers in the cloud such as Azure or AWS. My main challenges are precisely this issue of asynchronous patterns, I master them quite a bit but not to the level required for a responsible architecture that preserves the best practices. Obviously a node dedicated to processing jobs from the queue can use the default ThreadPool, the problem is when the user wants the same ASP.NET application to have a background IHostedService running the jobs. Hangfire fixes that with a schedule dedicated to job performance. Thanks for your reply Stephen.