【问题标题】:using Fail-fast approach when developing modular applications在开发模块化应用程序时使用快速失败的方法
【发布时间】:2012-05-05 00:48:29
【问题描述】:

在开发模块化应用程序时,很明显我们需要使用Fail-fast 系统吗?

在创建模块时,如果出现模块无法处理的错误情况,它应该报告错误(比如抛出异常..),而不用担心谁来处理它。看起来这可以作为开发模块时的指南。这有什么问题吗?

编辑:示例

在module.dll中

public class SomeClass:ISomeInterface
{

    public void CreateFile(string filename)
    {
       //The module have no idea who calls this. But there is something wrong        
       //somewhere so  throw an exception early. The module writer has no control over 
       //how the exception is handled. So if this exception is not handled by the 
       //Client Application the application can potentially crash.Do he need to worry 
       //about that?
       if(filename == null)
       {
          throw new ArgumentNullException("Filename is null");
       }

       //I think the following is bad. This code is making sure that a module 
       //exception wont crash the application.Is it good?
       //if(filename ==null)
       //{
       //Logger.log("filename is null");
       //return;
       //}
    }
 }

【问题讨论】:

    标签: c# wpf exception-handling error-handling modularity


    【解决方案1】:

    我可以看到两类严重异常:一类是整个系统可能已被破坏,并且没有太多可以安全假设的情况,另一类是系统的一个重要方面代码将期望“正常工作”,不会,但没有理由相信系统的其他部分受到损害。在前一种情况下,除了死机之外,程序实际上并没有什么可以做的,如果它可以在不破坏任何“主线”数据的情况下记录发生的事情,则可能会尝试记录发生的事情。但是,在后一种情况下,终止应用程序将过于“粗鲁”。恕我直言,更好的方法是设计子系统,以便代码可以“拔掉插头”以防止它导致数据损坏,结果是任何进一步尝试使用它(除了“你还在工作吗”查询,其返回值应该表明问题)可能会立即引发异常,但允许程序中不需要有问题的子系统的部分继续运行,除非或直到他们决定没有太多东西可供他们使用没有它。

    【讨论】:

    • +1,很有趣。我需要知道是否有任何方法可以杀死陷入困境的子系统?对于我们的应用程序,我们根据类型为 XML 文件提供了不同的 GUI 设计器。这些 GUI 设计器被创建为模块(子系统)。如果由于任何原因设计人员无法工作,我希望该特定设计人员不妨碍应用程序,让系统的其余部分按预期工作。但这里的问题是,如果子系统无法处理错误,子系统怎么会死掉?
    • @Jimmy:一种方法是拥有一个主IsAlive 属性(可能由_IsAlive 变量支持),并拥有将使用对象测试该变量的方法。另一种方法(也可以与IsAlive 一起使用)是使子系统的方法将要使用的字段无效,可能会将它们清空,或者可能用对虚拟对象的引用替换它们,这将在尝试时抛出更多信息异常使用它们。对于由锁保护的数据结构,将锁包装在包含“危险”标志和...的保护中可能很有用...
    • @Jimmy: ...有代码将(希望暂时)违反不变量,只要释放锁就应该保持不变,在违反不变量之前设置危险标志,并在何时清除它不变量被恢复。在设置了危险标志时在锁守卫上调用Dispose应该使底层数据结构无效,然后清除锁;因此,其他想要使用该数据结构的代码不会永远卡住等待永远不会释放的锁,但也不会访问损坏的数据。
    【解决方案2】:

    fail-fast 模块将处理错误但不检测错误的责任移交给下一个更高的系统设计级别

    来自维基百科的定义。 究竟是什么'下一个更高的系统设计水平'。这不应该至少是一个报告故障的级别,以便有人可以采取纠正措施并解决问题吗?在使用您的类的客户端代码提供的上层中实现。或者通过 AppDomain.UnhandledException 调用的通用错误报告器。两者都完全不受您的控制。

    抛出异常。

    【讨论】:

    • 存在 segfault/AV 并且上面的堆栈已损坏。你会冒险解开它吗?
    • Hmya,你要冒险举报吗?
    • +1,在大多数情况下,模块不会知道是什么导致了错误。这种情况下报错几乎是不可能的。我同意,抛出异常,不要担心谁来处理它。顺便说一句,我很难让人们同意这一点。
    • @HansPassant - 报告意味着赚更多的钱。展开意味着尝试使用退出堆栈。风险不一样。我不反对“找不到文件”或“套接字关闭”的例外情况,但对于“段错误/AV”,最好不要回到可能已经死掉的东西。我接受这一点,在大多数情况下,几个级别的异常处理程序将“安全地”从下面“安全地”获取一个 AV 异常,但这并不能保证。也许两者都做 - 将 e.message 附加到 'CriticalError.txt' 然后重新抛出。
    • 一个 AV 不需要任何帮助,Windows 已经处理好了。只是不要试图提供帮助。
    【解决方案3】:

    通常,当我在 C++ 中实现一个严重错误方案时,我不会让这些严重异常甚至离开异常处理程序——我调用一个全局可访问类实例的“criticalExit()”方法,(我通常有其中一个来存储“全局”方法等,例如记录器、对象池),但有一个例外和一个字符串(字符串通常只是模块和函数名称)。 criticalExit() 锁定互斥体,将其优先级提高到“THREAD_PRIORITY_TIME_CRITICAL”,打开“CriticalError.Log”,将异常消息和字符串附加到文件,关闭它并调用 ExitProcess(1),(Environment.Exit(1)) .

    ..而且,只是为了看看,我已经尝试在 C# 中执行此操作。生成全局可访问的单个实例并不容易:(

    【讨论】:

    • “模块化”系统是流行语。问这个问题的原因是这种情况几乎是“一刀切”的情况(如果模块真的设计为独立工作)。每个模块只关心自己的职责。如果应用程序使用模块,则应用程序负责将模块粘合在一起并处理错误。
    • 答案中解释的情况是在单体应用程序中(是吗?),我说的是模块
    • 模块是程序集内代码的逻辑集合。一个 C# 模块是 'CriticalErrorHandler' 并被其他模块调用并不是没有道理的。
    猜你喜欢
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多