Pregunta

archivos de registro Analizando me he dado cuenta de que ~ 1% de las llamadas de servicio terminó con TimeoutException en el lado del cliente de Silverlight. Los servicios (WCF) son bastante simples y no realizan cálculos largos. Según el registro de todas las llamadas a los servicios siempre se procesan en menos de 1 segundo (incluso cuando se produjo TimeoutException en el cliente!), Por lo que no es el tiempo de espera del servidor.

Así que lo que está mal? ¿Puede ser un problema de configuración o red? ¿Cómo puedo evitarlo? ¿Qué información adicional de registro puede ser útil para la localización de este problema?

El único solución que he pensado es hasta volver a intentar después de las llamadas de servicio de tiempo de espera.

apreciaré cualquier ayuda en este tema!

Actualización:. Al iniciar la aplicación realiza las llamadas de servicio 17 y 12 de ellos al mismo tiempo (? Puede ser causa de la falla)

Actualización: registro de WCF no ha contenido la información útil sobre este tema. Parece que algunas llamadas de servicio no alcanzan el lado del servidor.

¿Fue útil?

Solución

El problema está en el número máximo de conexiones simultáneas a un único servidor en Internet Explorer 7/6. Es solo 2! http://msdn.microsoft.com/en-us /library/cc304129(VS.85).aspx

Si tenemos 3 (por ej.) Servicio de llamadas concurrentes dos de ellos serán enviados al servidor de forma inmediata, pero el tercero lo estará esperando en la cola. También el temporizador de envío (correspondieron a sendTimeout) se ejecuta cuando la solicitud se encuentra en la cola. Si las dos primeras solicitudes de servicio va a correr por un largo tiempo, entonces el tercer generará TimeoutException aunque no se envía al servidor (y no vamos a ver ninguna información acerca de esta solicitud en el lado del servidor y no puede atraparla con Fiddler ...).

En la situación más real si tenemos cerca de 12 llamadas simultáneas y predeterminados 1 min envío de tiempo de espera y si las llamadas de servicio procesan más de 10 segundos en promedio, que fácilmente podemos obtener una excepción de tiempo de espera con las dos últimas llamadas (12/2 * 10 seg = 60 seg), ya que esperarán a todos los demás.

La solución es:

  1. Minimizar el número de llamadas de servicio concurrentes.
  2. Aumentar el valor sendTimeout en cliente config.
  3. Implementar función de reintento automático para servicios críticos.
  4. Implementar la cola de solicitudes para su gestión.

En mi caso, yo he hecho cosas 1-3 y eso fue suficiente.

Aquí está mi implementación de la función de reintento automático:

public static class ClientBaseExtender
{
    /// <summary>
    /// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again.
    /// </summary>
    /// <typeparam name="TChannel">ServiceClient class.</typeparam>
    /// <typeparam name="TArgs">Type of service client method return argument.</typeparam>
    /// <param name="client">ServiceClient instance.</param>
    /// <param name="tryExecute">Delegate that execute starting of service call.</param>
    /// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param>
    /// <param name="onCompleted">Delegate that executes when service call is succeeded.</param>
    /// <param name="onError">Delegate that executes when service call fails.</param>
    /// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param>
    public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute,
                                                               Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted,
                                                               EventHandler<TArgs> onError, int maxAttempts)
        where TChannel : class
        where TArgs : AsyncCompletedEventArgs
    {
        int attempts = 0;
        var serviceName = client.GetType().Name;

        onCompletedSubcribe((s, e) =>
                                {
                                    if (e.Error == null) // Everything is OK
                                    {
                                        if (onCompleted != null)
                                            onCompleted(s, e);

                                        ((ICommunicationObject)client).Close();
                                        Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now);
                                    }
                                    else if (e.Error is TimeoutException)
                                    {
                                        attempts++;

                                        if (attempts >= maxAttempts) // Final timeout after n attempts
                                        {
                                            Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now);

                                            if (onError != null)
                                                onError(s, e);
                                            client.Abort();

                                            Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
                                            return;
                                        }

                                        // Local timeout
                                        Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now);

                                        Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
                                        tryExecute(); // Try again.
                                    }
                                    else
                                    {
                                        if (onError != null)
                                            onError(s, e);
                                        client.Abort();
                                        Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
                                    }
                                });

        Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
        tryExecute(); // First attempt to execute
    }
}

Y aquí es un uso:

var client = new MyServiceClient();
client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...),
    (EventHandler<MyOperationCompletedEventArgs> handler) => client.MyOperationCompleted += handler,
    (s, e) => // OnCompleted
        {
            Do(e.Result);
        },
    (s, e) => // OnError
        {
            HandleError(e.Error);
        }
);

Esperamos que esto sea útil.

Otros consejos

¿Todavía tiene este problema?

Si es así, entonces tal vez debería ver la red con Fiddler o Microsoft Network Monitor o algo?

Mmmm ... puede ser posible que la petición / respuesta tarda más de 64 K o el exceso de objetos serializados?

Se puede tratar de hacer una simulación hiting el servidor con una aplicación de consola (sólo para comprobar si se trata de la red, SL ...)?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top