Автоматическое восстановление, когда общая сетевая ошибка DBNETLIB ConnectionWrite приводит к отключению соединений ADO в приложениях Delphi?


Гугление этого сообщения об ошибке ADO указывает на то, что оно обычно встречается в ASP.NET разработка, но я не нашел много упоминаний о том, когда это происходит в приложениях Delphi. У нас есть некоторые сайты клиентов, которые испытывают временные проблемы с сетью, и это симптоматическое сообщение об ошибке. Мы можем легко дублировать его в тестировании office; просто закройте службу MS SQL Server, пока ваш объект delphi TADOConnection подключен к базе данных на этом экземпляре сервера, и вы получите это исключение:

   [DBNETLIB][ConnectionWrite (send()).]General network error. Check your network documentation.

Да, поймайте это исключение, и вы знаете (или знаете?) что эта ошибка произошла. За исключением того, что это приложение 800 KLOC+ с более чем 10 000 блоков try-except вокруг действий базы данных, любой из которых может потерпеть неудачу с этой ошибкой.

TADOConnection имеет некоторые события ошибки, ни один из которых не срабатывает в этом случае. Однако само соединение ADO будет сброшено, как только это произойдет, даже если вы перезагрузите базу данных SQL, TADOConnection.Связь остается правдой, но это ложь. ты. Он действительно в неисправном состоянии.

Итак, мой вопрос:

можете ли вы обнаружить это сбойное состояние и восстановить его любым способом, который является менее трудоемким, чем вход в 10 000 отдельных блоков try-except и установка некоторой глобальной "reconnect ADO global variable"?

Я надеюсь, что есть способ войти в TADOConnection.ConnectionObject (базовый необработанный объект OLEDB COM ADO) и обнаружить это условие сбоя существует, когда мы начинаем новый запрос, таким образом, мы можем сбросить ADOConnection и продолжить в следующий раз, когда мы выполняем запрос. Поскольку наш код организован таким образом, что позволяет нам обнаружить это "после сбоя" гораздо легче, чем это позволило бы нам сделать это так, как я сделал бы это в 10-строчном демонстрационном приложении.

Этот другой вопрос SO спрашивает, почему это происходит, то есть не то, что я спрашиваю, пожалуйста, не давайте мне ответов "предотвращение", я уже знаю о них, я ищу восстановление и метод обнаружения застопорившегося соединения, отличный от перехвата исключений. На самом деле, это хороший пример исключений, которые пошли не так; ADO является объектом schrodingers-cat в этом режиме сбоя.

Я знаю о статьях базы знаний MS и различных решениях, плавающих в интернете. Я спрашиваю о восстановлении без потери данных клиента, как только состояние ошибки (которое часто является временным в наших ситуациях) очистится. Это означает, что мы замораживаем наше приложение, показываем исключение клиенту, и когда клиент нажимает кнопку Повторить или продолжить, мы пытаемся восстановить и продолжить. обратите внимание, что наш существующий код делает миллион попыток-кроме-лога-и-продолжения кода, который будет мешать нам, поэтому я ожидаю, что кто-то ответит, что обработчик приложения для необработанных исключений-это лучший способ, но, к сожалению, мы не можем его использовать. Я очень надеюсь, однако, что можно обнаружить замороженный/неисправный / мертвый объект соединения ADO.

Вот что у меня есть:

try
  if fQueryEnable and ADOConnection1.Connected then begin
    qQueryTest1.Active := false;
    qQueryTest1.Active := true;
    Inc(FQryCounter);
    Label2.Caption := IntToStr(qQueryTest1.RecordCount)+' records';

  end;
except
      on E:Exception do begin
         fQueryEnable := false;
         Memo1.Lines.Add(E.ClassName+' '+E.Message);
         if E is EOleException and Pos('DBNETLIB',E.Message)>0 then begin
            ADOConnectionFaulted := boolean; { Global variable. }
         end;
         raise;
      end;
end;

Проблема с вышеуказанным решением заключается в том, что мне нужно скопировать и вставить его примерно в 10 000 мест в моем приложении.

2 7

2 ответа:

Ну, никто не ответил на этот вопрос, и я думаю, что некоторые последующие действия были бы полезны.

Вот что я узнал:

  • Не существует надежных ситуаций, когда в тестовой среде можно воспроизвести эту общую сетевую ошибку. То есть, мы имеем дело с невоспроизводимыми результатами, в которых многие разработчики прыгают в злую хакерскую игру в попытке "обезьянничать" их сломанные системы.

  • Исправление основной ошибки всегда и везде было лучше, чем исправлять его в коде, когда библиотека SQL выдает "общую сетевую ошибку". Ни один ремонт никогда не был показан возможным, потому что обычно это означает, что "сеть настолько ненадежна, что TCP сам отказался от доставки моих данных", это происходит, когда:

    • У вас плохой сетевой кабель.

    • У вас есть дубликаты IP-адресов в сети.

    • У вас есть дуэли DHCP серверов каждый обрабатывает разные значения по умолчанию вороты.

    • У вас есть локальные сегменты ethernet, которые имеют плохую связь между собой.

    • У вас есть коммутатор ethernet или концентратор, который выходит из строя.

    • Вы периодически блокируетесь неисправным брандмауэром.

    • Возможно, ваш клиент что-то изменил в своей сети и теперь не может использовать ваше программное обеспечение. (Последнее на самом деле происходит чаще, чем вы могли бы подумать)

    • Кто-то, возможно, настроил псевдоним SQL, использующий cliconfg или другие элементы конфигурации на стороне клиента, специфичные для параметров реестра одной рабочей станции, и эта локальная конфигурация может привести к плохому поведению, которое трудно диагностировать и может быть ограничено одной или несколькими рабочими станциями в большой сети.

Ничего из вышеперечисленного не может быть обнаружено и сообщено ни на уровне TCP, ни на уровне SQL. Когда SQL, наконец, сдается, и это дает эту "общую сетевую ошибку", никакое количество уговоров из моего программного обеспечения собирается получить его un-give-up, и даже если бы это было так, я бы делал" try/except/ignore " антипаттерн. Эта ошибка настолько серьезна, что мы должны поднять ее до самого пользователя, записать ее на диск в журнале ошибок, отказаться (выйти из программы) и сообщить пользователю, что сетевое соединение не работает.

Я видел, что это происходит из-за плохого кодирования тоже..

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

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

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

Этот блог помог мне найти проблемы:

Http://offbeatmammal.hubpages.com/hub/Optimising_SQL_Server