Обработка исключений в критически важных приложениях, которые не должны падать - PullRequest
2 голосов
/ 16 августа 2010

У меня есть серверное приложение, которое я отлаживаю и которое в основном анализирует скрипты (VBscript, Python, Jscript и SQl) для приложения, которое его запрашивает.

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

Пример: в сценариях SQL приложение обычно возвращает набор значений (Дата, номер, строка и номер).Таким образом, сценарии должны иметь в конце следующее утверждение:

into dtDate, Number, Number, sString.Это значения, которые встроены в приложение, и серверное приложение знает, как их интерпретировать.Эти поля обрабатываются в приложении сервера как часть массива.Возвращаемые значения обычно должны быть в определенном порядке, так как индексы для этих полей в массиве жестко закодированы внутри серверного приложения.

Теперь, когда пользователь, пишущий скрипт, забывает одно из этих полей, тогда последнее поле (обычно строка) генерирует исключение IndexOutofBoundsException.

Вопрос в том, как можно восстановиться после исключений такого рода, не удаляя приложение?

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

Это серверное приложение является родным приложением C ++ и использует технологии COM.

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

Ответы [ 6 ]

2 голосов
/ 16 августа 2010

, так как вы говорите о разборе разных языков, у вас, вероятно, есть что-то вроде

class IParser //parser interface
{
  virtual bool Parse( File& fileToParse, String& errMessage ) = 0;
};

class VBParser : public Parser
class SQLParser : public Parser

Предположим, что метод Parse () генерирует исключение, которое не обрабатывается, все ваше приложение падает. Вот упрощенный пример того, как это можно исправить на уровне приложения:

  //somewhere main server code
void ParseFileForClient( File& fileToParse )
{
  try
  {
    String err;
    if( !currentParser->Parse( fileToParse, err ) )
      ReportErrorToUser( err );
    else
      //process parser result
  }
  catch( std::exception& e )
  {
    ReportErrorToUser( FormatExceptionMessage( err ) );
  }
  catch( ... )
  {
    ReportErrorToUser( "parser X threw unknown exception; parsing aborted" );
  }
}
2 голосов
/ 16 августа 2010

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

Для обеспечения того, чтобы изменения не дестабилизировали критическое бизнес-приложение, требуется организация. Люди, которые подписывают изменения и проверяют, что они работают, как предполагалось, прежде чем они будут допущены в производство. QA.

0 голосов
/ 16 августа 2010

Если у вас есть сервер.У вас в основном есть основной цикл, который ждет сигнала, чтобы начать работу.Сигнал может быть ничем, и ваш сервер просто просматривает список файлов в файловой системе, или он может быть больше похож на веб-сервер, где он ожидает подключения и выполняет сценарий, предоставленный для подключения (или любую другую вещь).

MainLoop()
{
    while(job = jobList.getJob())
    {
         job.execute();
    }
}

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

MainLoop()
{
    // Don't bother to catch exceptions from here.
    // This probably means you have a programming error in the server.
    while(job = jobList.getJob())
    {
        // Catch exception from job.execute()
        // as these exceptions are generally caused by the script.
        try
        {
            job.execute();
        }
        catch(MyServerException const& e)
        {
            // Something went wrong with the server not the script.
            // You need to stop. So let the exception propagate.
            throw;
        }
        catch(std::exception const& e)
        {
            log(job, e.what());
        }
        catch(...)
        {
            log(job, "Unknown exception!");
        }
    }
}

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

0 голосов
/ 16 августа 2010

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

SaveStateThatCanBeAlteredByScript();
try {
    LoadScript();
} catch(std::exception& e){
    RestoreSavedState();
    ReportErrorToUser(e);
}
FreeSavedState();

Если вы хотите предотвратить сбой внешнего кода(возможно, ненадежный код, такой как плагины), вам нужна схема IPC.В Windows, я думаю, вы можете использовать файлы карты памяти с OpenFile().На POSIX-системах вы можете использовать sem_open() вместе с mmap().

0 голосов
/ 16 августа 2010

Это действительно зависит от того, сколько времени потребуется для запуска вашего серверного приложения. Может быть безопаснее позволить приложению аварийно завершить работу и затем перезагрузить его. Или, воспользовавшись браузером Chrome, запустите разные части вашего приложения в разных процессах, которые могут привести к сбою. Если вы можете безопасно восстановить исключение и верить, что с вашим приложением все в порядке, хорошо, сделайте это. Однако перехват std :: exception и continue может быть рискованным.

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

Bluepill http://asemanfar.com/Bluepill:-a-new-process-monitoring-tool

кардиостимулятор http://www.clusterlabs.org/

0 голосов
/ 16 августа 2010

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

Как правило, вам нужно писать код безопасным способом, который обычно использует следующие рекомендации

  • Работа с временными значениями, которые могут генерировать исключения
  • Зафиксируйте изменения, используя временные значения после (обычно это не вызывает исключения)

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

http://www.gotw.ca/gotw/056.htm

http://www.gotw.ca/gotw/082.htm

...