Question

I'm trying to do some async stuff in a webservice method. Let say I have the following API call: http://www.example.com/api.asmx

and the method is called GetProducts().

I this GetProducts methods, I do some stuff (eg. get data from database) then just before i return the result, I want to do some async stuff (eg. send me an email).

So this is what I did.

[WebMethod(Description = "Bal blah blah.")]
public IList<Product> GetProducts()
{
    // Blah blah blah ..
    // Get data from DB .. hi DB!
    // var myData = .......
    // Moar clbuttic blahs :)  (yes, google for clbuttic if you don't know what that is)

    // Ok .. now send me an email for no particular reason, but to prove that async stuff works.
    var myObject = new MyObject();
    myObject.SendDataAsync();

    // Ok, now return the result.
    return myData;
    }
}

public class TrackingCode
{
    public void SendDataAsync()
    {
        var backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += BackgroundWorker_DoWork;
        backgroundWorker.RunWorkerAsync();
        //System.Threading.Thread.Sleep(1000 * 20);
    }

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        SendEmail();
    }
}

Now, when I run this code the email is never sent. If I uncomment out the Thread.Sleep .. then the email is sent.

So ... why is it that the background worker thread is torn down? is it dependant on the parent thread? Is this the wrong way I should be doing background or forked threading, in asp.net web apps?

Was it helpful?

Solution

BackgroundWorker is useful when you need to synchronize back to (for example) a UI* thread, eg for affinity reasons. In this case, it would seem that simply using ThreadPool would be more than adequate (and much simpler). If you have high volumes, then a producer/consumer queue may allow better throttling (so you don't drown in threads) - but I suspect ThreadPool will be fine here...

public void SendDataAsync()
{
    ThreadPool.QueueUserWorkItem(delegate
    {
        SendEmail();
    });
}

Also - I'm not quite sure what you want to achieve by sleeping? This will just tie up a thread (not using CPU, but doing no good either). Care to elaborate? It looks like you are pausing your actual web page (i.e. the Sleep happens on the web-page thread, not the e-mail thread). What are you trying to do here?

*=actually, it will use whatever sync-context is in place

OTHER TIPS

Re producer/consumer; basically - it is just worth keeping some kind of throttle. At the simplest level, a Semaphore could be used (along with the regular ThreadPool) to limit things to a known amount of work (to avoid saturating the thread pool); but a producer/consumer queue would probably be more efficient and managed.

Jon Skeet has such a queue here (CustomThreadPool). I could probably write some notes about it if you wanted.

That said: if you are calling off to an external web-site, it is quite likely that you will have a lot of waits on network IO / completion ports; as such, you can have a slightly higher number of threads... obviously (by contrast) if the work was CPU-bound, there is no point having more threads than you have CPU cores.

It may torn down because after 20 seconds, that BackgroundWorker instance may be garbage collected because it has no references (gone out of scope).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top