/// <summary>
        /// Close an existing client
        /// </summary>
        /// <param name="client">client to dispose</param>
        private static void DisposeClient(ref VertexCallbackServiceClient client)
        {
            if (client != null)
            {
                try
                {
                    client.Close();
                }
                catch (Exception)
                {
                    try
                    {
                        client.Abort();
                    }
                    catch (Exception)
                    {
                        // If client cannot be aborted, just finish silently.
                    }
                }

                client = null;
            }
            else
            {
                throw new ArgumentNullException("client");
            }
        }
        /// <summary>
        /// Attempt to call SetGetPropsComplete on specified WCF service.
        /// </summary>
        /// <param name="replyUri">Service endpoint</param>
        /// <param name="systemProcess"></param>
        /// <param name="processId"></param>
        /// <param name="info"></param>
        /// <param name="propertyLabels"></param>
        /// <param name="propertyVersions"></param>
        /// <returns></returns>
        public static bool SetGetPropsComplete(string replyUri, Process systemProcess, int processId, ProcessInfo info, string[] propertyLabels, ulong[] propertyVersions)
        {
            DryadLogger.LogMethodEntry(replyUri, processId);

            bool result = false;

            VertexCallbackServiceClient client = GetClient(replyUri);

            //
            // Try to set/get properties up to numRetries times
            //
            for (int index = 0; index < numRetries; index++)
            {
                try
                {
                    //
                    // If client is null, try reopening it
                    //
                    if (client == null)
                    {
                        client = CreateClient(replyUri);
                    }

                    //
                    // Make SetGetPropsComplete WCF call, return success
                    //
                    client.SetGetPropsComplete(processId, info, propertyLabels, propertyVersions);
                    result = true;
                    break;
                }
                catch (Exception e)
                {
                    if ((IsGraphMrgUri(replyUri) == false && systemProcess.HasExited) || shuttingDown)
                    {
                        //
                        // If trying to connect to non-running vertex or job is shutting down, don't retry and report success.
                        //
                        DisposeClient(ref client);
                        return(true);
                    }
                    else
                    {
                        //
                        // If call failed and talking to GM or running vertex process, try reopening WCF client and calling again
                        //
                        client = ReopenClientForRetry(replyUri, e);
                    }
                }
            }

            //
            // If failed to connect X times, report error
            //
            DryadLogger.LogMethodExit(result);
            return(result);
        }
        /// <summary>
        /// Notify GM that vertex host process exited
        /// </summary>
        /// <param name="replyUri">GM address</param>
        /// <param name="processId">vertex process id</param>
        /// <param name="exitCode">reason for vertex host exit</param>
        /// <returns>success/failure</returns>
        public static bool ProcessExited(string replyUri, int processId, int exitCode)
        {
            DryadLogger.LogMethodEntry(replyUri, processId, exitCode);

            bool result = false;

            VertexCallbackServiceClient client = GetClient(replyUri);

            //
            // Try to notify GM that the process has exited up to numRetries times
            //
            for (int index = 0; index < numRetries; index++)
            {
                try
                {
                    //
                    // If client is null, try reopening it
                    //
                    if (client == null)
                    {
                        client = CreateClient(replyUri);
                    }

                    //
                    // Make ProcessExited WCF call, return success
                    //
                    client.ProcessExited(processId, exitCode);
                    result = true;
                    break;
                }
                catch (Exception e)
                {
                    if (shuttingDown)
                    {
                        // if shutting down, just return
                        DisposeClient(ref client);
                        return(true);
                    }
                    else
                    {
                        //
                        // If call failed, try reopening WCF client and calling again
                        //
                        client = ReopenClientForRetry(replyUri, e);
                    }
                }
            }

            //
            // If failure occurs after X retry attempts, report error
            //
            DryadLogger.LogMethodExit(result);
            return(result);
        }
        /// <summary>
        /// Helper method to retry opening the client for use with state changes and property comm
        /// </summary>
        /// <param name="replyUri">URI to respond to</param>
        /// <param name="e">Reason for retry</param>
        /// <returns>new client - may be null on failures</returns>
        private static VertexCallbackServiceClient ReopenClientForRetry(string replyUri, Exception e)
        {
            VertexCallbackServiceClient client = null;

            DryadLogger.LogError(0, e);
            try
            {
                client = ReopenClient(replyUri);
            }
            catch (Exception reopenEx)
            {
                DryadLogger.LogError(0, reopenEx, "Unable to reopen client connection");
            }

            //
            // If retrying, sleep briefly
            //
            System.Threading.Thread.Sleep(retrySleepTime);

            return(client);
        }
        /// <summary>
        /// Try to reopen client to WCF service
        /// </summary>
        /// <param name="uri">Address of service</param>
        /// <returns>new client</returns>
        private static VertexCallbackServiceClient ReopenClient(string uri)
        {
            lock (syncRoot)
            {
                //
                // Get any existing client to this URI
                //
                VertexCallbackServiceClient client = GetClient(uri);
                if (client != null)
                {
                    //
                    // If a client exists, dispose it
                    //
                    DisposeClient(ref client);
                }

                //
                // Recreate the client
                //
                return(CreateClient(uri));
            }
        }
        /// <summary>
        /// Creates a new WCF client to service listening at URI
        /// </summary>
        /// <param name="uri">wcf service endpoint</param>
        /// <returns>client to WCF service</returns>
        private static VertexCallbackServiceClient CreateClient(string uri)
        {
            VertexCallbackServiceClient client = new VertexCallbackServiceClient(binding, new EndpointAddress(uri));

            lock (syncRoot)
            {
                //
                // If the graph manager URI is specified, store this client as the GM client, otherwise assume it's a vertex host
                //
                if (IsGraphMrgUri(uri))
                {
                    graphMgrUri    = uri;
                    graphMgrClient = client;
                }
                else
                {
                    vertexProcUri    = uri;
                    vertexProcClient = client;
                }
            }

            return(client);
        }