Best way to decouple (for parallel processing) a w

2019-05-10 01:05发布

I'm looking for a good strategy to truly decouple, for parallel processing, my web application's (ASP.NET MVC/C#) non-immediate processes. I define non-immediate as everything that doesn't require to be done right away to render a page or update information.

Those processes include sending email, updating some internal statistics based on database information, fetching outside information from web services which only needs to be done periodically and so forth.

Some communication needs to exist between the main ASP.NET MVC application and those background tasks though; e.g. the MVC application needs to inform the emailing process to send something out.

What is the best strategy to do this? MSMQ? Turn all those non-immediate processes into windows services? I'm imagining a truly decoupled scenario, but I don't want a trade off that makes troubleshooting/unit testing much harder or introduces vast amounts of code.

Thank you!

10条回答
在下西门庆
2楼-- · 2019-05-10 01:15

Simplest way to handle async processing in ASP.NET is to use the ThreadPool to create a worker that you hand your work off to. Be aware that if you have lots of small jobs you are trying to hand-off quickly, the default ThreadPool has some annoying lock contention issues. In that scenario, you either need to use C# 4.0's new Stealing ThreadPool, or you can use MindTouch's Dream library which has a Stealing Threadpool implementation (along with tons of other async helpers) and works with 3.5.

查看更多
我命由我不由天
3楼-- · 2019-05-10 01:16

We've done this with the workflow API, or if it's not imperative that it it execute you could use a simple delegate.BeginInvoke to run this on a background thread.

查看更多
淡お忘
4楼-- · 2019-05-10 01:18

ThreadPool in .NET is queue based worker pool, however its used internally by ASP.NET host process, so if you try to utilize ThreadPool more, you may reduce performance of Web Server.

So you must create your own thread, mark it as background and let it poll every few seconds for job availability.

The best way to do is, create a Job Table in database as follow,

Table: JobQueue
JobID (bigint, auto number)
JobType (sendemail,calcstats)
JobParams (text)
IsRunning (true/false)
IsOver (true/false)
LastError (text)

JobThread class could be like following.

class JobThread{
    static Thread bgThread = null;
    static AutoResetEvent arWait = new AutoResetEvent(false);

    public static void ProcessQueue(Job job)
    {
         // insert job in database
         job.InsertInDB();

         // start queue if its not created or if its in wait
         if(bgThread==null){
              bgThread = new Thread(new ..(WorkerProcess));
              bgThread.IsBackground = true;
              bgThread.Start();
         }
         else{
              arWait.Set();
         }
    }

    private static void WorkerProcess(object state){
         while(true){
              Job job = GetAvailableJob( 
                        IsProcessing = false and IsOver = flase);
              if(job == null){
                   arWait.WaitOne(10*1000);// wait ten seconds.
                                           // to increase performance
                                           // increase wait time
                   continue;
              }
              job.IsRunning = true;
              job.UpdateDB();
              try{

              //
              //depending upon job type do something...
              }
              catch(Exception ex){
                   job.LastError = ex.ToString(); // important step
                   // this will update your error in JobTable
                   // for later investigation
                   job.UpdateDB();
              }
              job.IsRunning = false;
              job.IsOver = true;
              job.UpdateDB();
         }
    }
}

Note This implementation is not recommended for high memory usage tasks, ASP.NET will give lots of memory unavailability errors for big tasks, like for example, we had lot of image uploads and we needed to create thumbnails and process them using Bitmap objects, ASP.NET just wont allow you to use more memory so we had to create windows service of same type.

By creating Windows service you can create same thread queue and utilize more memory easily, and to make communication between ASP.NET and Windows Service you can use WCF or Mutex objects.

MSMQ MSMQ is also great, but it increases configuration tasks and it becomes difficult to trace errors sometimes. We avoid MSMQ because lot of time we spend looking for an answer of problem in our code where else MSMQ configuration is problem and the errors sometimes dont give enough information of where exactly is the problem. In our custom solution we can create full debugger version with logs to trace errors. And thats biggest advantage of Managed Programs, in earlier Win32 apps, the errors were really difficult to trace.

查看更多
Bombasti
5楼-- · 2019-05-10 01:19

If you can develop for .NET 4 Framework then you can decouple by using F# or the Parallel Computing features (http://msdn.microsoft.com/en-us/library/dd460693(VS.100).aspx)

F# is designed to support parallel computing so it may be a better choice than moving code into services.

Though, if you wanted, you could just use WCF and off-load everything to webservices, but that may not really solve your problem as it just moves the issues elsewhere.

EDIT: Moving the non-essential to webservices may make the most sense then, and this is a standard practice where the webserver is outside of the firewall, so vulnerable, so all the real work is done by other servers, and the webserver is just responsible for static pages and rendering.

You can use Spring.NET for this, if you don't want to add webservices, but either way you are largely just calling a remote process to do the work.

This is scalable as you can separate the business logic to several different servers, and since the webserver is largely just the view part of MVC it can handle more requests than if all the MVC work is in the webserver.

Because it is designed for this, Spring.NET should be easier to test, but, webservices can also be tested, as you should test each part separately, then do functional tests, but, by using Spring.NET it is easier to mock out levels.

查看更多
我命由我不由天
6楼-- · 2019-05-10 01:21

Nservicebus sounds like it might be applicable here, though under the covers it'd probably use msmq. Essentially you sound like you're after doing asynchronous stuff, which .net has good mechanisms for dealing with.

查看更多
一纸荒年 Trace。
7楼-- · 2019-05-10 01:25

MSMQ is an awesome way to do this. A web farm can feed requests into one or more queues. The queues can be serviced by one or more processes on one or more servers giving you scale and dedundancy. (Run MSMQ on a cluster if you want to remove the single point of failure). We did this about 8-9 years back and it was awesome watching it all run :) And even back then MSMQ was dead simple to use (from COM) -- I have to imagine things have only gotten better with .NET.

查看更多
登录 后发表回答