Question

I'm having a hard time trying to get my task to stay persistent and run indefinitely from a WCF service. I may be doing this the wrong way and am willing to take suggestions.

I have a task that starts to process any incoming requests that are dropped into a BlockingCollection. From what I understand, the GetConsumingEnumerable() method is supposed to allow me to persistently pull data as it arrives. It works with no problem by itself. I was able to process dozens of requests without a single error or flaw using a windows form to fill out the request and submit them. Once I was confident in this process I wired it up to my site via an asmx web service and used jQuery ajax calls to submit request.

The site submits request based on a url that is submitted, the Web Service downloads the html content from the url and looks for other urls within the content. It then proceeds to create a request for each url it finds and submits it to the BlockingCollection. Within the WCF service, if the application is Online (i.e. Task has started) - it pulls the request using the GetConsumingEnumerable via a Parallel.ForEach and Processes the request.

This works for the first few submissions, but then the task just stops unexpectedly. Of course, this is doing 10x more request than I could simulate in testing - but I expected it to just throttle. I believe the issue is in my method that starts the task:

 public void Start()
        {
            Online = true;

            Task.Factory.StartNew(() =>
            {
                tokenSource = new CancellationTokenSource();
                CancellationToken token = tokenSource.Token;
                ParallelOptions options = new ParallelOptions();
                options.MaxDegreeOfParallelism = 20;
                options.CancellationToken = token;

                try
                {
                    Parallel.ForEach(FixedWidthQueue.GetConsumingEnumerable(token), options, (request) =>
                    {
                        Process(request);
                        options.CancellationToken.ThrowIfCancellationRequested();

                    });
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine(e.Message);
                    return;
                }

            }, TaskCreationOptions.LongRunning);

        }

I've thought about moving this into a WF4 Service and just wire it up in a Workflow and use Workflow Persistence, but am not willing to learn WF4 unless necessary. Please let me know if more information is needed.

Was it helpful?

Solution

The code you have shown is correct by itself.

However there are a few things that can go wrong:

  • If an exception occurs, your task stops (of course). Try adding a try-catch and log the exception.
  • If you start worker threads in a hosted environment (ASP.NET, WCF, SQL Server) the host can decide arbitrarily (without reason) to shut down any worker process. For example, if your ASP.NET site is inactive for some time the app is shut down. The hosts that I just mentioned are not made to have custom threads running. Probably, you will have more success using a dedicated application (.exe) or even a Windows Service.

OTHER TIPS

It turns out the cause of this issue was with the WCF Binding Configuration. The task suddenly stopped becasue the WCF killed the connection due to a open timeout. The open timeout setting is the time that a request will wait for the service to open a connection before timing out. In certain situations, it reached the limit of 10 max connection and caused the incomming connections to get backed up waiting for a connection. I made sure that I closed all connections to the host after the transactions were complete - so I gave in to upping the max connections and the open timeout period. After this - it ran flawlessly.

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