プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

Windowsサービスを作るときに自動回復に頼りすぎてはいけない話

今回もやらかしネタをネタにしています。相変わらずちゃんとした裏どりはしていないのであまり信じすぎないでください。

自動回復オプション

Windowsサービスには自動回復のオプションがあります。基本的にWindowsサービスとして実行したいアプリケーションは常時起動している必要があるからサービスにしているわけで、停止していることがばれたら困るアプリの最後の砦として重宝します。クライアントアプリなどは操作中に落ちたら再起動をユーザーがすぐにしてくれますが、サービスの場合はそれが難しいですからね。

.NET Framework時代

太古の昔、C#( .NET Framework )でWindowsサービスを作ろうとしたときに重宝したのが Topshelf というライブラリで、コンソールアプリとして動かすこともできるしそのままサービスとして動かすこともできる、とても素晴らしいものでした。

先に書きましたがサービスとして動かすアプリですから、簡単に落ちてしまっては困ります。コード内で例外をキャッチしまくって落ちないようにするわけですね。

ですがなんでもかんでも例外を拾って無理やり動かしていても、ただ落ちていないだけで正常に動き続けているわけではないサービスになってしまい、最終的に落ちているよりたちが悪い状況を引き起こすかもしれません。

そこでWindowsサービスの自動回復の登場です。想定される(復旧可能な)例外はアプリ内で拾って、想定外の例外はそのまま放置でアプリを落としてしまいます。落ちたサービスはWindowsが指定時間後に再起動してくれるので、想定外だったけど再起動で直るような現象をこれでカバーしていました。

.NET 時代

現在Windowsサービスを作ろうと思ったら、Visual Studioで「ワーカー サービス」のテンプレートを使ってUseWindowsService()でしょう。

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .UseWindowsService()
    .Build();

host.Run();

これでWorkerの中でいろいろ処理をやるわけですが、今まで通りWindowsが指定時間後に再起動してくれるつもりで例外を拾わない、ように作ってしまうとやってしまいます。

これはログに

The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted.
Application is shutting down...

訳(?)「例外拾ってなくてBackgroundService 続けられないから終わるわ」

と出ているように、正常に終了しているのでWindowsはサービスがエラーで終了したとは認識してくれないからです。

自動回復の恩恵を受ける方法

継続不可能っぽいので再起動したいときにどうするのかというと簡単で

Environment.Exit(-1);

を呼ぶだけでいけます。かなり乱暴な方法なので最後の手段にしましょう。呼ぶときも解放できるリソースはできるだけ解放してからにしましょう。

というやらかしネタでした。

おしまい