5

I am trying to open a proxy on a thread (in background), the thread makes a new instance of the proxy, calls a method of the service and immediately after disposes the service.

All of this happens on a thread :

var background = new Thread(() =>
{
    var proxy = new AssignmentSvcProxy(new EndpointAddress(worker.Address));              

    try
    {
        proxy.Channel.StartWork(workload);
        proxy.Dispose();                   
    }
    catch (EndpointNotFoundException ex)
    {
        logService.Error(ex);                        
        proxy.Dispose();
        proxy = null;
    }
    catch (CommunicationException ex)
    {
        logService.Error(ex);
        proxy.Dispose();
        proxy = null;
    }
    catch (TimeoutException ex)
    {
        logService.Error(ex);                    
        proxy.Dispose();
        proxy = null;
    }
    catch (Exception ex)
    {
        logService.Error(ex);                    
        proxy.Dispose();
        proxy = null;
    }                

}) { IsBackground = true };

background.Start();

I keep seeing intermittent timeout issues happening even though I have set the timeout to max for CloseTimeout, OpenTimeout, ReceiveTimeout, SendTimeout.

I just want to make sure design wise this is not an issue i.e. opening a service on a thread and disposing it?

EDIT :

Proxy internally establishes a channel with custom binding on different endpoints for each thread.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
Murtaza Mandvi
  • 10,708
  • 23
  • 74
  • 109
  • It's a bit confusing that you speak of "Service" where I'd expect "Proxy" (or even "Client"), e.g. "the thread opens the service" should be "the thread opens a proxy for my service", right? – Jeroen Oct 19 '12 at 15:46
  • Sorry, I just updated the question, so basically my service is already open but yes the proxy just calls the proxy.Channel.StartWork(workload); of that particular service (which is already self hosted) - makes sense? – Murtaza Mandvi Oct 19 '12 at 15:54
  • you might want to add a `finally` to your try-catch clause. finally executes code even though an exception is thrown. Regarding your issue, I'm uncertain. I also believe it would be wise to pass your binding into the constructor. this might be the cause of your timeout exception. – Rik van den Berg Oct 19 '12 at 16:31
  • How many of these threads do you kick off? Or just this one? – Science_Fiction Oct 19 '12 at 20:47
  • Why are spinning yourself a thread? I would go for either asynchronous methods or TPL – VJAI Oct 22 '12 at 15:22
  • Where is this "proxy", did you code it yourself and does it support multiple congruent connections or a backlog? Your timeouts may be due to one connection being made and the others being blocked by that initial connection. Just a thought. – vane Oct 23 '12 at 15:31

1 Answers1

6

I think the issue may be in that you are not properly closing the proxies. If you have lots of threads hitting the server and they are not all cleaning up after themselves, you may get some timeouts on those connections.

Dispose is not ideal for closing connections. More information here: Disposing proxies

The ideal pattern to use is as follows:

try
{
    proxy.Close();
}
catch (Exception ex)
{
    proxy.Abort();
}
finally
{
    proxy = null;
}

You attempt to close the connection, if it fails, you abort all connections. Dispose does not abort if there is an exception.

As such, I would refactor like so:

var background = new Thread(() =>
{
     var proxy = new AssignmentSvcProxy(new EndpointAddress(worker.Address));              

    try
    {
        proxy.Channel.StartWork(workload);
    }
    catch (Exception ex)
    {
        // You aren't doing anything special with your specific exception types
        logService.Error(ex);                    
    }                
    finally
    {
        try
        {
            proxy.Close();
        }
        catch (Exception ex)
        {
            proxy.Abort();
        }
        finally
        {
            proxy = null;
        }
    }

}) { IsBackground = true };

background.Start();
Community
  • 1
  • 1
Bardia
  • 317
  • 4
  • 9
  • 1
    This works. However, WCF proxies are thread safe (concurrent calls are serialized). Since creating a proxy and opening a new connection to the server is an expensive operation, usually proxies are reused across threads. – Marcel N. Aug 05 '14 at 23:42
  • I agree, which is why he should ideally have a retry mechanism in case the connection fails for whatever reason. This pattern in the failure handling would then ensure the old connection is cleaned up before being forced to create a new one. – Bardia Aug 06 '14 at 18:34