тайм-аут блокировки во времени в веб-сервисе c # - PullRequest
2 голосов
/ 13 июля 2011

Мой веб-сервис имеет этот код

lock(typeof MyWebServiceClass)

Ну, я называю неизменяемый код третьей стороны, и он никогда не возвращается. БУМ! БАМ!

Я заблокирован навсегда, и мой веб-сайт падает.

Это никогда не возвращается, случается только один раз.

Можно ли создать блокировку с тайм-аутом? IE заблокировать код на 5 минут, затем снять блокировку?

Ответы [ 3 ]

2 голосов
/ 13 июля 2011

Вместо создания временной блокировки я бы ограничил ваш сторонний запрос, поместив его в отдельный поток / задачу. Затем начните цепочку (или задачу, если вам доступны .NET 4.0 и TPL) и присоединитесь к ответу с таймаутом. Если время соединения истекло, отмените цепочку (или вызовите маркер отмены в задаче TPL).

0 голосов
/ 13 июля 2011

Если у стороннего API есть механизм отмены, используйте его.

lock(typeof MyWebServiceClass)
{
  if (ThirdPartyApiThatAcceptsTimeout(TimeSpan.FromMinutes(5)))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    return;
  }
}

Однако я очень подозреваю, что у этого API нет механизма отмены, и именно поэтому вы задали этот вопрос. Если это так, то это стало экспоненциально сложнее.

Наивным подходом было бы отложить вызов API другому потоку. Если поток не отвечает своевременно, вы можете прервать его.

lock(typeof MyWebServiceClass)
{
  var thread = new Thread(
    () =>
    {
      ThirdPartyApiThatCouldBlockIndefinitely();
    });
  thread.Start();
  if (thread.Join(TimeSpan.FromMinutes(5))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    thread.Abort();
    return;
  }
}

Хотя с этим много проблем. Во-первых, нет никакой гарантии, что поток примет запрос на прерывание. Начиная с 2.0 в CLR есть специальные правила, которые определяют, когда прерывания могут быть введены в поток. Я считаю, что CLR будет откладывать внедрение, пока выполняется неуправляемый код. Так что если ваш API неуправляемый, то прерывание может не работать. Кроме того, прерывания являются добровольными, поскольку поток может перехватить ThreadAbortException и игнорировать его. Во-вторых, прерывание опасно, поскольку прерывание может быть введено асинхронно. Это очень затрудняет защиту от повреждения общего состояния. Вот почему AppDomain обычно завершается после прерывания.

Самый безопасный способ справиться с этим - поместить вызов API в отдельный процесс. Вы должны будете использовать протоколы межпроцессного взаимодействия, такие как .NET Remoting, WCF, каналы и т. Д. Для передачи данных в / из вызова, что будет очень трудно поддерживать. Но это будет самым безопасным, поскольку вы можете безопасно завершить процесс без риска повреждения AppDomain вызывающей стороны.

Я действительно чувствую к вам, потому что эту проблему действительно трудно решить правильно.

0 голосов
/ 13 июля 2011

Можно ли создать блокировку с тайм-аутом?

Да, эту неприятную ситуацию часто называют тупик .

Обычно рекомендуется блокировать статический закрытый объект вместо блокировки полей экземпляра или самого класса:

private static object _syncRoot = new object();

и затем:

lock(_syncRoot) {

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...