2011-06-29 16 views
8

Mam aplikację czasu rzeczywistego, która śledzi zasoby wokół wielu witryn w całym kraju. W ramach tego rozwiązania mam 8 aplikacji klienckich, które aktualizują serwer centralny.Najlepszy sposób na pokonanie limitu czasu WCF

Moje pytanie brzmi: czasami aplikacje tracą połączenie z centralnym serwerem i zastanawiam się, jaki jest najlepszy sposób, aby sobie z tym poradzić? Wiem, że mogłem po prostu zwiększyć maksymalne czasy wysyłania/odbierania, aby poradzić sobie z przekroczeniem limitu czasu, ALE również chcę uzyskać wdzięczne rozwiązanie, jeśli połączenie z serwerem jest wyłączone:

Na przykład nazywam moje usługi w ten sposób :

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

myślałem o dodanie try/catch tak ...

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

Radzenie sobie to w ten sposób nie pozwala mi ponownie uruchomić kod bez konieczności mnóstwo powtórzenia kodu. Ktoś ma jakieś sugestie?

EDYTOWANIE: Patrząc na odpowiedzi Sixto Saez i user24601, posiadanie ogólnego rozwiązania jest lepsze niż rozwiązywanie problemów z przekroczeniem limitu czasu na indywidualnym poziomie wyjątku, ALE ... Myślałem, że poniższe rozwiązanie rozwiąże mój problem (ale doda TON dodatkowych błędów obsługi kodu):

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; 
} 
+0

Można napisać funkcję, która sprawdzi, czy serwer jest uruchomiony, w ten sposób można sprawdzić, czy serwer jest uruchomiony, zanim zostanie nawiązane połączenie z repozytorium. Możesz także zajrzeć do wyglądu serwera. – Jethro

+0

Stwórz więc funkcję rekursywną, która nie wyjdzie, dopóki serwery się nie zakończą ... i wyskoczysz przed wywołaniem wcf? Podoba mi się ten pomysł i byłby to mniejszy kod niż powyższa edycja. Twój pomysł zdecydowanie poprawia niezawodność 99%, ale jak poradziłbym sobie, gdyby serwer utracił połączenie między czekiem a wywołaniem metody? –

+0

@Jethro: Najlepsze praktyki odradzają stosowanie metody ping. Zobacz dyskusję tutaj: http://stackoverflow.com/questions/2166356/how-to-check-if-a-wcf-service-is-operational Podstawową ideą jest to, że timeout może być wynikiem zależności usługowej, 't pojawiają się w zdarzeniu ping (takim jak usługa WCF, która współdziała z bazą danych, w której baza danych powoduje przekroczenie limitu czasu). – VoteCoffee

Odpowiedz

3

Na początek Myślę, że obsługa błędów Wcf jest błędna. Powinien on wyglądać tak, jakbym ponownie wyświetlił błąd, aby poinformować użytkownika o problemie. Powrót na górę

+0

Jakie korzyści daje mi operowanie zamykaniem/zamykaniem w momencie automatycznego odpalenia garbage collectora po zakończeniu instrukcji użytkowania? –

+1

Oto [dobry post] (http://geekswithblogs.net/DavidBarrett/archive/2007/11/22/117058.aspx), aby przeczytać o Dispose realizacji wzór w WCF i dlaczego nigdy nie należy używać z wykorzystaniem statment to, –

1

Przed zaprojektowaniem obsługi wyjątku, jedną ważną decyzją do podjęcia jest to, czy chcesz zagwarantować dostarczenie każdej wiadomości, którą klient wysyła, czy też jest ona w porządku, aby usługa "straciła" trochę. Dla guaranteed delivery, najlepszym wbudowanym rozwiązaniem jest netMsmqBinding, zakładając, że klient może być skonfigurowany do obsługi go. W przeciwnym razie wbudowany w WCF jest lekki reliable messaging capability. Będziesz schodząc do króliczej nory, jeśli starają się obsłużyć dostarczanie wiadomości wyłącznie przez obsługę wyjątków ... :)

+0

Dzięki temu zajrzę –

2

Mam dwutorowe podejście do weryfikacji serwera wynosi:

1) I skonfigurowałem "PING" na serwerze co 5 sekund. Serwer odpowiada "PONG" i ocena obciążenia (niska, średnia, wysoka, aby klient mógł dostosować swoje obciążenie na serwerze). Jeśli klient KIEDYKOLWIEK nie otrzymuje ponga, zakłada, że ​​serwer jest wyłączony (ponieważ jest to bardzo mały stres na serwerze - po prostu słuchaj i odpowiadaj).

2) Losowe limity czasu, takie jak ten, który przechwytujesz, są rejestrowane w klasie ConnectionMonitor razem ze wszystkimi udanymi połączeniami. Jeden z tych limitów czasu nie wystarcza, aby rozważyć serwer, ponieważ niektóre z nich mogą być bardzo ciężkie dla procesora lub może zająć bardzo dużo czasu. Jednak wystarczająco wysoki procent tych aplikacji spowoduje przekroczenie limitu czasu serwera.

Nie chciałem też podawać wiadomości dla każdego limitu czasu połączenia, ponieważ działo się to zbyt często dla osób, które korzystają z gorszych serwerów (lub tylko z komputera leżącego w ich laboratorium jako serwer). Większość moich połączeń może zostać pominiętych raz lub dwa razy, ale brak 5 lub 6 wywołań wyraźnie spowoduje zakłócenia.

Po wystąpieniu stanu przekroczenia czasu serwera wyświetlam okno dialogowe wyjaśniające, co dzieje się z użytkownikiem.

1

Witam Proszę zobaczyć moje rozwiązanie poniżej. Zwróć też uwagę, że poniższy kod nie został uzupełniony, więc może zawierać błędy logiczne i literowe.

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 
} 
} 
Powiązane problemy