处理不应崩溃的关键应用程序中的异常

时间:2010-08-16 14:43:34

标签: c++ com exception-handling

我有一个我正在调试的服务器应用程序,它基本上为请求它的应用程序解析脚本(VBscript,Python,Jscript和SQl)。

这是一个非常关键的应用程序,如果崩溃导致许多用户遭受破坏。我面临的问题是如何处理异常,以便应用程序可以继续,并且用户知道脚本中是否有错误。

示例:在SQL脚本中,应用程序通常返回一组值(日期,数字,字符串和数字)。所以脚本必须在最后有一个声明:

into dtDate, Number, Number, sString。这些是内置于应用程序中的值,服务器应用程序知道如何解释这些值。这些字段在服务器应用程序中作为数组的一部分进行处理。返回值通常应按特定顺序排列,因为数组中这些字段的索引在服务器应用程序内是硬编码的。

现在,当用户编写脚本忘记其中一个字段时,最后一个字段(通常是字符串)会抛出IndexOutofBoundsException。

问题是如何在不取消申请的情况下从这种性质的异常中恢复?

另一个例子是脚本中的错误,其中不能生成错误解析消息。这些错误在应用程序的后台消失,最终导致服务器应用程序崩溃。它失败的脚本不一定完全没有执行,但是它的一部分没有执行而其他部分没有执行,这使得用户看起来很奇怪。

此服务器应用程序是本机C ++应用程序并使用COM技术。

我想知道是否有人对如何处理异常(例如上述异常而不会导致应用程序崩溃)的最佳方法有任何想法?

6 个答案:

答案 0 :(得分:2)

您无法使用例外处理此类问题。你可以拥有一个能够捕获异常的顶级catch块,并希望没有太多的程序状态无法恢复,以试图让程序保持活跃状态​​。仍然没有让用户满意,她正在等待的查询仍然无法运行。

确保更改不会破坏关键业务应用程序的稳定需要组织。签署更改并在允许生产之前验证它们是否按预期工作的人员。 QA。

答案 1 :(得分:2)

因为你谈到解析不同的语言,你可能有类似

的东西
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 :(得分:0)

如果您知道某个操作可以抛出异常,那么您需要在此区域添加异常处理。

基本上,您需要以异常安全的方式编写代码,通常使用以下指南

  • 处理可能引发异常的临时值
  • 之后使用临时值提交更改(通常这不会引发异常)

如果在处理临时值时抛出异常,则不会有任何损坏,在异常处理中您可以管理情况并恢复。

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

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

答案 3 :(得分:0)

这实际上取决于启动服务器应用程序所需的时间。让应用程序崩溃然后重新加载它可能更安全。或者从Chrome浏览器中获取提示,在可能崩溃的不同进程中运行应用程序的不同部分。如果您可以安全地恢复异常并相信您的应用程序状态正常,那么就可以了。然而,捕获std :: exception并继续进行可能会有风险。

婴儿坐着过程有简单到复杂的方法,以确保它们崩溃后可以重新启动。我使用的一些工具。

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

心脏起搏器http://www.clusterlabs.org/

答案 4 :(得分:0)

对于由于用户错误而在程序内部发生的简单异常, 只需保存可以更改的状态,并将其恢复如下:

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

如果你想防止外部代码崩溃(可能是不可信的代码,比如插件),你需要一个IPC方案。在Windows上,我认为您可以使用OpenFile()存储地图文件。在POSIX系统上,您可以将sem_open()mmap()一起使用。

答案 5 :(得分:0)

如果您有服务器。你基本上有一个等待信号启动工作的主循环。信号可能没什么,你的服务器只是通过文件系统上的文件列表,或者它可能更像是一个Web服务器,它等待连接并执行连接上提供的脚本(或任何类似的东西)。

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!");
        }
    }
}

如果服务器对您的操作至关重要,那么仅检测问题并记录它并不总是足够的。写得不好的服务器会崩溃,因此您希望自动执行恢复。因此,您应该编写某种形式的心跳过程,定期检查进程是否已崩溃以及是否已自动重新启动它。