Ciaran O'Neill
Ciaran O'Neill

Reputation: 2634

Pro's and cons for MVC 3 background processing

I need to do some audio processing in an MVC 3 application and would like to know the pro's & cons of the different these different background methods. The audio processing as a general rule will be a long running process so I'd just like to make sure IIS is free to handle other requests.

  1. AsyncController & background worker

    public ActionResult GetAudioCompleted(byte[] audio)
    {
    return File(audio, "audio/wav", "mywavfile.wav");
    }
    
    public void GetAudioAsync()
    {          
        BackgroundWorker w = new BackgroundWorker();
        w.RunWorkerCompleted += (s, e) =>
        {
            AsyncManager.Parameters["audio"] = e.Result;
            AsyncManager.OutstandingOperations.Decrement();
        };
        w.DoWork += (s, e) =>
        {      
            byte[] b;       
            using (var ms = new MemoryStream())
            {
                // Process audio to memory stream
    
                ms.Seek(0, SeekOrigin.Begin);
                b = new byte[ms.Length];
                ms.Read(b, 0, (int)ms.Length);
                e.Result = b;
            }
        };
        AsyncManager.OutstandingOperations.Increment();
        w.RunWorkerAsync();            
    }
    
  2. AsyncController & Task

    public ActionResult GetAudioCompleted(byte[] audio)
    {
        return File(audio, "audio/wav", "mywavfile.wav");
    }
    
    public void GetAudioAsync()
    {            
        AsyncManager.OutstandingOperations.Increment();
        var t = Task<byte[]>.Factory.StartNew(() =>
        {
            byte[] b;
            using (var ms = new MemoryStream())
            {
                // Process audio to memory stream
                ms.Seek(0, SeekOrigin.Begin);
                b = new byte[ms.Length];
                ms.Read(b, 0, (int)ms.Length);
            }
            return b;
        })
        .ContinueWith(c =>
            {
                AsyncManager.Parameters["audio"] = c.Result;
                AsyncManager.OutstandingOperations.Decrement();
            });          
    }
    
  3. Non async controller & Thread

    public ActionResult GetaAudio()
    {
        byte[] b;
    
        using (var ms = new MemoryStream())
        {
            var t = Thread(() =>
                {
                    // Process audio to memory stream
                });
            t.Start();
            t.Join();
    
            // error checking etc.
            ms.Seek(0, SeekOrigin.Begin);
            b = new byte[ms.Length];
            ms.Read(b, 0, (int)ms.Length);
            return File(b, "audio/wav", "mywavfile.wav");
        }
    }
    

Questions:

  1. Are BackgroundWorkers recommended for use in web applications?
  2. If I use the Tasks, does this this background thread use one from the IIS threadpool, (maybe negating one of the benefits of this approach as a thread is not released for request processing)?
  3. Using a System.Threading.Thread - does this thread use one from the IIS threadpool. Does t.Join() block the current IIS thread?

Which approach would seem better to you and why? Any other approaches are welcome.

Upvotes: 1

Views: 633

Answers (1)

Dai
Dai

Reputation: 155250

  1. No. ASP.NET and IIS executes each HTTP request/response on its own thread. Asynchronous programming in ASP.NET is more about doing more work per request (such as executing unrelated SQL queries on separate threads), not about handling threading the request.

  2. I don't know, I'm not too familiar with Tasks.

  3. Yes, and yes.

I would do it like this (psuedocode):

  1. I'd take the file to process and then process that in a background thread (using a straightforward System.Threading.Thread instance), this means the IIS request/response thread isn't blocked and can return HTML to the client immediately.
  2. I'd store a token or reference somewhere to this file-process job. I would then return a 303 redirect to "/processingJobs/job123" (where job123 is the job ID).
  3. The actionHandler for GET processingJobs would look up the background thread for job 123 and see if it's complete, if it is not complete then it returns a HTML response saying "your job is being processed, please refresh the page again for updated status", along with a little javascript that refreshes the page every 5-10 seconds.
  4. If the job is complete, then return the processed audio file with a content-disposition: header.

This technique scales up well, or even infinitely if audio processing is handled by a separate process or by a queue system rather than doing them all simultaneously.

A general guideline: if a HTTP request/response cannot be completed within 100ms then do the job in the background and immediately return a status message.

Upvotes: 2

Related Questions