Лучший способ справиться с тайм-аутом WCF - PullRequest
8 голосов
/ 29 июня 2011

У меня есть приложение в реальном времени, которое отслеживает активы на нескольких сайтах по всей стране. В рамках этого решения у меня есть 8 клиентских приложений, которые обновляют центральный сервер.

Мой вопрос заключается в том, что иногда приложения теряют связь с центральным сервером, и мне интересно, как лучше всего с этим справиться? Я знаю, что мог бы просто увеличить максимальное время отправки / получения, чтобы справиться с тайм-аутом, НО я также хочу иметь изящное решение, если соединение с сервером не работает:

Например, я звоню в мои службы так:

using (var statusRepository = new StatusRepositoryClient.StatusRepositoryClient())
{
    statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
}

Я думал о добавлении try / catch, чтобы ...

using (var statusRepository = new StatusRepositoryClient.StatusRepositoryClient())
{
    try
    {
       statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    }
    catch (TimeoutException timeout)
    {
       LogMessage(timeout);
    }
    catch (CommunicationException comm)
    {
       LogMessage(comm);
    }
}

Работа с этим способом не позволяет мне перезапускать код без повторения тонны кода. У кого-нибудь есть предложения?

РЕДАКТИРОВАТЬ: Глядя на ответы Sixto Saez и user24601, имея общее решение, лучше, чем иметь дело с тайм-аутами на уровне отдельного исключения, НО ... Я думал, что приведенное ниже решит мою проблему (но добавит TON дополнительной обработки ошибок кода):

void Method(int statusId)
{
     var statusRepository = new StatusRepositoryClient.StatusRepositoryClient()

      try
      {
         IsServerUp();
         statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
         statusRepository.Close(); 
      }            
      catch (Exception ex)
      {
            statusRepository.Abort();

            if (ex is TimeoutException || ex is CommunicationException)
            {
              LogMessage(timeout);
              Method(statusId);
            }
            else
            {
                throw new Exception(ex.Message + ex.InnerException);
            }
        }

  }
}

bool IsServerUp()
{
    var x = new Ping();
    var reply = x.Send(IPAddress.Parse("127.0.0.1"));

    if (reply == null)
    {
       IsServerUp();
    }
    else
    {
       if (reply.Status != IPStatus.Success)
       {
          IsServerUp();
       }
    }

    return true;
}

Ответы [ 4 ]

3 голосов
/ 29 июня 2011

Для начала я думаю, что ваша обработка ошибок Wcf неверна.Это должно выглядеть следующим образом:

var statusRepository = new StatusRepositoryClient.StatusRepositoryClient();
try
{
    statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    statusRepository.Close()
}
catch(Exception e)
{
   statusRepository.Abort();
   LogMessage(e);
   throw; //I would do this to let user know.
}

Я бы еще раз выдал ошибку, чтобы сообщить пользователю о проблеме.

2 голосов
/ 29 июня 2011

У меня есть двунаправленный подход к проверке работоспособности сервера:

1) Я установил 'PING' к серверу каждые 5 секунд.Сервер отвечает «PONG» и рейтингом нагрузки (низкая, средняя, ​​высокая, чтобы клиент мог регулировать свою нагрузку на сервер).Если клиент НИКОГДА не получает понг, он предполагает, что сервер не работает (так как это очень низкий уровень нагрузки на сервер - просто слушайте и отвечайте).

2) Случайные тайм-ауты, такие как тот, который вы ловитевошел в класс ConnectionMonitor вместе со всеми успешными соединениями.Одного из этих тайм-аутов вызовов недостаточно для того, чтобы считать сервер неработоспособным, поскольку некоторые из них могут быть слишком загружены процессором или могут занимать очень много времени.Однако достаточно высокий процент из них приведет к тому, что приложение перейдет в состояние тайм-аута сервера.

Я также не хотел выдавать сообщение для каждого тайм-аута соединения, потому что это происходило слишком часто с людьми, которыеиспользуйте более бедные серверы (или просто какой-нибудь компьютер, лежащий в их лаборатории в качестве сервера).Большинство моих вызовов могут быть пропущены один или два раза, но пропущенные 5 или 6 вызовов явно вызовут вторжение.

Когда происходит состояние тайм-аута сервера, я вырываю небольшое диалоговое окно, объясняющее, что происходит спользователь.

1 голос
/ 29 июня 2011

Привет Пожалуйста, посмотрите мое решение ниже.Также обратите внимание, что приведенный ниже код не был скомпилирован, поэтому могут быть некоторые ошибки логики и опечатки.

bool IsServerUp()
{
    var x = new Ping();
    var reply = x.Send(IPAddress.Parse("127.0.0.1"));

if (reply == null) return false;

return reply.Status == IPStatus.Success ? true : false;
} 

int? GetStatusId()
{
try 
{
    using (var statusRepository = new  StatusRepositoryClient.StatusRepositoryClient())
    {
        return statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    }
}catch(TimeoutException te)
{
    //Log TimeOutException occured
    return null;
}
}

void GetStatus()
{
try
{
    TimeSpan sleepTime = new TimeSpan(0,0,5);
    int maxRetries = 10;

    while(!IsServerUp())
    {
        System.Threading.Thead.Sleep(sleepTime);
    }

    int? statusId = null;
    int retryCount = 0;

    while (!statusId.HasValue)
    {
        statusId = GetStatusId();
        retryCount++;

        if (retryCount > maxRetries)
            throw new ApplicationException(String.Format("{0} Maximum Retries reached in order to get StatusId", maxRetries));
        System.Threading.Thead.Sleep(sleepTime);
    }
}catch(Exception ex)
{
    //Log Exception Occured
}
} 
1 голос
/ 29 июня 2011

Прежде чем приступить к разработке обработки исключений, необходимо принять одно важное решение: хотите ли вы гарантированную доставку каждого сообщения, отправляемого клиентом, или это нормально для службы, чтобы «потерять» ее. Для гарантированной доставки, лучшим встроенным решением является netMsmqBinding, предполагая, что клиент может быть настроен для его поддержки. В противном случае в WCF встроена облегченная функция надежного обмена сообщениями . Вы попадете в кроличью нору, если попытаетесь обработать доставку сообщений исключительно с помощью обработки исключений ...:)

...