web-dev-qa-db-ja.com

未処理の例外を処理する方法は? (アプリケーションを終了するか、存続させるか)

デスクトップアプリケーションで未処理の例外が発生した場合のベストプラクティスは何ですか?

ユーザーにメッセージを表示して、サポートに連絡できるようにすることを考えていました。ユーザーにアプリケーションを再起動することをお勧めしますが、強制しないでください。ここで説明されているものに似ています: x.stackexchange.com-予期しないアプリケーションエラーを処理する最良の方法は何ですか?

プロジェクトは.NET WPFアプリケーションであるため、説明されている提案は次のようになります(これは簡略化された例であることに注意してください。ユーザーが[詳細を表示]をクリックしていくつかの機能を提供するまで例外の詳細を非表示にすることは理にかなっています簡単にエラーを報告してください):

public partial class App : Application
{
    public App()
    {
        DispatcherUnhandledException += OnDispatcherUnhandledException;
    }

    private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        LogError(e.Exception);
        MessageBoxResult result = MessageBox.Show(
             $"Please help us fix it and contact [email protected]. Exception details: {e.Exception}" +
                        "We recommend to restart the application. " +
                        "Do you want to stop the application now? (Warning: Unsaved data gets lost).", 
            "Unexpected error occured.", MessageBoxButton.YesNo);

        // Setting 'Handled' to 'true' will prevent the application from terminating.
        e.Handled = result == MessageBoxResult.No;
    }

    private void LogError(Exception ex)
    {
        // Log to a log file...
    }
}

実装(ViewModelsのコマンドまたは外部イベントのイベントハンドラー)では、特定の外因性例外のみをキャッチし、他のすべての例外(骨付きおよび不明な例外)を上記の「最後の手段ハンドラー」にバブルアップさせます。骨のある外因性の例外の定義については、以下を参照してください。 Eric Lippert-Vexing exceptions

アプリケーションを終了するかどうかをユーザーに決定させることは理にかなっていますか?アプリケーションが終了すると、不整合な状態はなくなります。一方で、アプリケーションが再起動されるまで、ユーザーは保存されていないデータを失うか、開始された外部プロセスを停止できなくなります。

または、作成しているアプリケーションのタイプに応じて、未処理の例外でアプリケーションを終了する必要があるかどうかの決定ですか? Code Complete、Second Edition で説明されているように、「堅牢性」と「正確性」のトレードオフですか?

どのようなアプリケーションについて話しているのかをコンテキストに説明します。アプリケーションは主に、化学実験装置を制御し、測定結果をユーザーに表示するために使用されます。これを行うには、WPFアプリケーションが一部のサービス(ローカルサービスおよびリモートサービス)と通信します。 WPFアプリケーションは機器と直接通信しません。

30
Jonas Benz

とにかく、停電やシステム全体をクラッシュさせる別のバックグラウンドプロセスなど、未処理の例外以外の理由でプログラムが終了することを期待する必要があります。したがって、私はアプリケーションを終了して再起動することをお勧めしますが、いくつかの方法でこのような再起動の結果を軽減するおよびデータ損失の可能性を最小限に抑えるです。

次の点を分析することから始めます。

  • プログラムが終了した場合、実際にどれだけのデータが失われる可能性がありますか?

  • そのような損失は本当にユーザーにとってどれほど深刻ですか?失われたデータは5分未満で再構築できますか、それとも1日分の仕事を失うことについて話しているのでしょうか。

  • 「中間バックアップ」戦略を実装するのにどれだけの労力が必要ですか?コメントに書いたように、通常の保存操作では「ユーザーは変更理由を入力する必要がある」ので、これを除外しないでください。プログラムが自動的にクラッシュした後に再ロードされる一時ファイルや状態のようなものを考えた方がよいでしょう。多くのタイプの生産性ソフトウェアがこれを行います(たとえば、MS OfficeとLibreOfficeの両方に「自動保存」機能とクラッシュリカバリがあります)。

  • データが間違っているか破損している場合、ユーザーはこれを簡単に確認できますか(プログラムの再起動後など)。はいの場合、ユーザーがデータを保存できるようにするオプションを提供し(少しの可能性がありますが破損します)、再起動を強制し、データを再ロードして、ユーザーがデータに問題がないか確認できるようにします。古いバージョンの破損を避けるために、定期的に保存された最後のバージョンを上書きしないでください(代わりに一時的な場所/ファイルに書き込みます)。

そのような「中間バックアップ」戦略が賢明なオプションであるかどうかは、最終的にはアプリケーションとそのアーキテクチャ、および関連するデータの性質と構造に依存します。しかし、ユーザーが10分未満の作業を失うと、そのようなクラッシュが1週間に1回、またはそれ以上発生することがほとんどない場合、私はおそらくこれにあまり多くの投資をしないでしょう。

47
Doc Brown

ある程度は開発中のアプリケーションに依存しますが、一般的に、アプリケーションで未処理の例外が発生した場合は、それを終了する必要があると思います。

どうして?

アプリケーションの状態に自信が持てなくなるため

間違いなく、helpfulメッセージをユーザーに提供しますが、最終的にはアプリケーションを終了する必要があります。

あなたのコンテキストを考えると、私は間違いなくアプリケーションを終了したいと思います。ラボで実行されているソフトウェアが破損した出力を生成することを望んでおらず、例外を処理することを考えていなかったため、例外がスローされた理由と何が起こっているのかわかりません。

30
Matthew

これは化学実験室向けであり、アプリケーションが機器を直接制御するのではなく、他のサービスを通じて制御することを考慮してください。

メッセージを表示した後、強制終了します。未処理の例外の後、アプリケーションは不明な状態になります。誤ったコマンドを送信する可能性があります。 鼻の悪魔 を呼び出すこともできます。 誤ったコマンドは、高価な試薬を無駄にしたり、機器や人に危険をもたらしたりする可能性があります

しかし、あなたは何か他のことをすることができます:再起動後に正常に回復します。アプリケーションがクラッシュしたときに、アプリケーションがバックグラウンドサービスをダウンさせることはないと思います。その場合、それらから簡単に状態を回復できます。または、さらに状態がある場合は、保存することを検討してください。データの原子性と整合性を備えたストレージ内(SQLiteかどうか)。

編集:

コメントに記載されているように、ユーザーが反応する時間がないほど速く制御するプロセスを変更する必要がある場合があります。その場合は、正常な状態の回復に加えて、サイレントにアプリを再起動することを検討する必要があります。

12
Jan Dorniak

プログラムのトップレベルで一般的にこの質問に答えようとするのは賢いやり方ではありません。

何かがずっと泡立っていて、アプリケーションのアーキテクチャーのどの時点でもこのケースを誰も考慮していなかった場合、どのアクションが安全であるか、または安全でないかについて行うことができる一般化はありません。

したがって、いいえ、アプリケーションと開発者が、それが可能かどうか、または賢明かどうかを確認するために必要な十分な注意を払っていないため、アプリケーションが回復を試みるかどうかをユーザーが選択できるようにすることは、一般的に許容できる設計ではありません。 。

ただし、アプリケーションに、この種の障害回復を念頭に設計されたロジックまたは動作の重要な部分があり、この場合にそれらを活用できる場合は、必ずそうしてください-その場合、ユーザーにリカバリを試行するかどうか、または単に終了して最初からやり直すかどうかを確認するようプロンプトを表示することは許容される場合があります。

この種の回復は、一般にすべての(またはほとんどの)プログラムに必要または推奨されませんが、この程度の操作の整合性が必要なプログラムで作業している場合、この種の回復を提示する状況になる可能性があります。ユーザーにプロンプ​​トを出すのは正気なことです。

特別な障害回復ロジックの代わりに-いいえ、これを行わないでください。あなたは文字通り何が起こるかわからない、もしそうしたなら、あなたは例外をさらに下に捕らえてそれを処理したでしょう。

8
Iron Gremlin

「例外的な例外」、つまり予期していなかった例外の問題は、プログラムの状態がわからないことです。たとえば、ユーザーのデータを保存しようとすると、実際にはさらに多くのデータを破棄します

そのため、アプリケーションを終了する必要があります。

Crash-only SoftwareGeorge CandeaとArmando Fox と呼ばれる非常に興味深いアイデアがあります。アイデアは、ソフトウェアを閉じる唯一の方法がクラッシュすることであり、それを開始する唯一の方法がクラッシュからの回復であるような方法でソフトウェアを設計する場合、ソフトウェアはより回復力があり、エラー回復になるということです。コードパスは、より徹底的にテストおよび実行されます。

一部のシステムは、通常のシャットダウン後よりもクラッシュ後に速く起動したことに気づき、彼らはこのアイデアを思いつきました。

もう適切な例ではありませんが、クラッシュからの回復時に起動が速くなるだけでなく、起動時のエクスペリエンスが向上する古いバージョンのFirefoxもいくつかあります!これらのバージョンでは、Firefoxを正常にシャットダウンすると、開いているすべてのタブが閉じて、1つの空のタブで起動します。クラッシュから回復する場合、クラッシュ時に開いていたタブを復元します。 (そして、それが現在のブラウジングコンテキストを失わずにFirefoxを閉じる唯一の方法でした。)では、人々は何をしましたか?彼らは単にFirefoxを閉じず、代わりに常にpkill -KILL firefoxed。

Linux Weekly NewsのValerie Auroraによるクラッシュのみのソフトウェアに関する素晴らしい記事 があります。コメントも一読の価値があります。たとえば、コメントの誰かがそれらのアイデアは新しいものではなく、実際には多かれ少なかれErlang/OTPベースのアプリケーションの設計原則と同等であると指摘しています。そしてもちろん、これを今日見ると、ヴァレリーから10年後、元の記事から15年後のことですが、現在のマイクロサービスの誇大宣伝が同じアイデアを再考していることに気付くかもしれません。最新のクラウドスケールのデータセンター設計も、より粗い粒度の例です。 (どのコンピュータでも、システムに影響を与えることなくいつでもクラッシュする可能性があります。)

ただし、ソフトウェアをクラッシュさせるだけでは不十分です。それのために設計する必要があります。理想的には、ソフトウェアは小さな独立したコンポーネントに分割され、それぞれが独立してクラッシュする可能性があります。また、「クラッシュメカニズム」は、クラッシュするコンポーネントの外部にある必要があります。

3
Jörg W Mittag

ほとんどの例外を処理する適切な方法は、結果として破損状態にある可能性のあるオブジェクトを無効にし、無効化されたオブジェクトがそれを妨げない場合は実行を継続することです。たとえば、リソースを更新するための安全なパラダイムは次のようになります。

acquire lock
try
  update guarded resource
if exception
  invalidate lock
else
  release lock
end try

保護されたリソースの更新中に予期しない例外が発生した場合、例外が他の点で害のないタイプであるかどうかに関係なく、リソースは破損した状態であると推定され、ロックは無効になります。

残念ながら、IDisposable/usingを介して実装されたリソースガードは、ブロックが正常に終了したか異常に終了したかを知る方法がなく、ガードされたブロックが終了するたびに解放されます。したがって、例外の後でいつ続行するかについて明確に定義された基準があるはずですが、それらがいつ適用されるかを知る方法はありません。

1
supercat

すべてのiOSおよびMacOSアプリが従うアプローチを使用する場合があります。キャッチされない例外は、アプリケーションをすぐに停止します。さらに、配列の範囲外や新しいアプリケーションでの算術オーバーフローなどの多くのエラーでも同じことが行われます。警告なし。

私の経験では、多くのユーザーは何も気にせず、アプリのアイコンをもう一度タップします。

明らかに、そのようなクラッシュが重大なデータ損失につながらず、間違いなくコストのかかる間違いにつながらないことを確認する必要があります。しかし、「アプリがすぐにクラッシュします。問題が発生した場合はサポートに連絡してください」というメッセージは誰にも役立たない。

0
gnasher729