views:

3058

answers:

5

Hi Folks, I'm trying to do some async stuff in a webservice method. Let say i have the following API call: http://www.mysite.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 u 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?

cheers ;)

+5  A: 

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

Marc Gravell
The sleep is commented out. I put that, there, to see if i could send an email. when the sleep is UNCOMMENTED, then the background worker thread code is executed. when the code is comented out, then the background worker thread code is never executed.I'll try using ThreadPool instead.
Pure.Krome
A: 

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

huseyint
Note that the Sleep() is on the web-page thread; it is more likely that the BackgroundWorker is trying to use a sync-context that is being blocked by the Sleep() itself
Marc Gravell
A: 

@Marc Gravell:

If you have high volumes, then a producer/consumer queue may allow better throttling (so you don't drown in threads)

ooooooo!!! i'm glad u actually raised this point! the web service method is actually high volume! also, to make matters really interesting, it's not really sending an email, but actually hitting another external website (ekk, don't ask) ... so you would suggest i do this producer/consumer queue thingy? If so ... is this a good page to reference?

http://www.albahari.com/threading/part4.aspx (please scroll down a fair bit to the code + an example).

thoughts?

edit: fixed typo with Marc's name. Sincere appologies there mate. Was not intentional.

Pure.Krome
"Gravel", that's just mean.
bzlm
seeks - that was a typo. most definately not intentional. ..... fixed! *sorry marc ... i didn't mean it.*
Pure.Krome
+1  A: 

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.

Marc Gravell
A: 

The work is most definitely Network IO stuff. In fact, i'm actually making a server side google analytics 'urchin' recording code. it's really simple, actually .. which surprises me that it's not be done before.

Because this is server side, this is to be used (by us) in some API calls (eg. web service method). This way, we can track our API hits using google analytics. (at least, that's the theory).

So .. right now our API is getting smashed (which is awesome!). I don't want to add in this little call to record to google that we've been 'hit' .. which adds some huge 'net lag'. As such, i wanted to make the call async ... and to do that i wanted to do it in another thread. But the trick here is that i wanted to 'finish' the web service method successfull, while the background thread or background queue is 'recording' the hit to google analytics.

So what you're suggesting is that this could be done with the P/C thread concept ... which means we're limiting the number of threads because everything is being added to a queue (nice) and those limited number of threads are popping this queue.. etc. Otherwise, i'll be drowning in new threads per api hit (which are lots in a short period), as u suggested.

if it looks like i'm understanding your ideas ... this keeps coming back to the concept of a background thread (or background P/C threads) 'working' in a C# web service model --- can this be done? can i make a webservice method which sends the result back to the consumer .. while some background thread computes some logic. If this has gone offtrack, i can ask a new q :)

Pure.Krome