Windowsサービスはどのようにしてプログラム的に再起動できますか?


135

Windowsサービス(サーバー2003)がそれ自体を再起動できるようにするには、.NETで堅牢なコードを記述する必要があります。これを行うための最良の方法は何ですか?それを行うためのいくつかの.NET APIはありますか?


7
「ロバスト」とはイタチの言葉です(stackoverflow.fogbugz.com/default.asp?W13086)-どのような特性が必要ですか?
エイダンライアン

回答:


187

失敗後にサービスを再起動するように設定します(コントロールパネルでサービスをダブルクリックし、タブを見回してください-名前を忘れました)。次に、サービスを再起動したいときはいつでもEnvironment.Exit(1)(またはゼロ以外の戻り値を)呼び出すだけで、OSがサービスを再起動します。


7
場所はサービスパネルにあります。問題のサービスを右クリックしてプロパティを選択し、[リカバリ]タブを選択します。
James Michael Hare

20
これで望ましい動作がどのように実現されるかはわかりますが、戻りコード1は、エラーが発生したことをシステムに通知するためのものです。実際にはエラーがなく、サービスを再起動したいだけの場合、これは悪い習慣ではありませんか?
mgttlinger 2013年

4
これは、インストール後のイベントでサービスインストーラーによってプログラムで実行できます。クリックする必要はありません...サービスがリモートサーバー上にあり、たとえばテスト中に1日に数回インストールする必要がある場合はどうでしょうか。
Dean Kuga

5
@mgttlinger:そうだと思います。サービスが正常な場合は悪い習慣なので、再起動する必要はありません。しかし、一部のサービスアーキテクチャは手の届かない範囲にあり、それらを再起動する必要がある場合、それがうまくいかないという症状です。サービスが不適切に実行されると、状況が悪化する(役に立たない)可能性があります。
ルチアーノ

5
@JohnLeidegren適切なシャットダウンが必要な場合は、を設定してService.ExitCode = 1からService.Stop()、サービスリカバリ設定画面の[エラーのあるストップのアクションを有効にする]チェックボックスをオンにして実行できます。この方法でこれを行うと、適切なシャットダウンが可能になり、再起動がトリガーされます。
クリス・ライス

22
Dim proc As New Process()
Dim psi As New ProcessStartInfo()

psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()

3
サービス名にスペースが含まれている場合は、サービス名の前後に「」を追加してください。
apc 2015

4
これは、特権アカウントで実行されているサービス専用であり、とにかく悪い考えです。
Dmitry Gusarov

17

サービスを実行しているユーザーアカウントに、サービスを停止および再起動するためのアクセス許可があるかどうかを確認することはできません。


同じ問題に直面したときに+1されましたが、sc.exeを見ると、OpenSCManager()を呼び出すときにSERVICE_QUERY_CONFIGをdwDesiredAccessとして使用し、SERVICE_START |でOpenService()を呼び出していることがわかりました。SERVICE_STOPは特定のサービスを開き、正常に動作します(アクセスに問題はありません)。これを.NETでどのように実行できるかについてはわかりません。
n0p 2015年

ほとんどのWindowsサービスはシステムとして実行されるため、問題にはなりません。
切り替え

@Switch NETWORK SERVICEの下で実行されるサービスの巨大なサークルがあります。デフォルトでは、独自の実行可能ファイルを開く権限さえありません。
AgentFire

@AgentFire、正解ですが、デフォルトはネットワークサービスではなくローカルシステムです。ローカルシステムには、オペレーティングシステムに対して本質的に最高レベルの特権があり、ローカルのAdministratorsグループのメンバーに割り当てられている特権を超えています。
切り替え

@Switchですが、最も利用可能な権限を使用すると、PoL 原則に違反します。
AgentFire

12

自分を再起動するDOSコマンドプロンプトであるプロセスを作成できます。

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();

これは、他に何もせずに、呼び出しスレッドのセキュリティコンテキストを継承します。再起動するのに十分な処理能力があるコンテキストである限り、問題ありません。
クレイ

12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

どこSERVICENAMEあなたのサービスの名前です(サービス名にスペースが、そうでない場合は省略することができるため、二重引用符は、アカウントに含まれています)。

クリーンで、自動再起動構成は必要ありません。


9
[Command1を]&[Command1を]は&& [command2の]は、実行が成功した場合のみCommand1を実行する(COMMAND2ながら[command2の]は常に、順次両方のコマンドを実行します:およそ&&&対何か新しいことを学んだautoitscript.com/forum/topic/...を
ジェフリーをナイト

5

再起動する理由によって異なります。

サービス自体を定期的にクリーンアップする方法を探しているだけなら、定期的にパージルーチンを引き起こすタイマーをサービスで実行することができます。

障害時に再起動する方法を探している場合-サービスホスト自体は、セットアップ時にその機能を提供できます。

では、なぜサーバーを再起動する必要があるのでしょうか。何を達成しようとしていますか?


1
ラージオブジェクトヒープとメモリの断片化に関心がある場合、これは機能しません。おそらく.NET 4 / 4.5および64ビットのプロセスがこれに大きく貢献しています。
David Kassa 2013

3

自己完結型のサービスではできないと思います(Restartを呼び出すと、サービスが停止して、Restartコマンドが中断され、再び開始されることはありません)。2番目の.exe(ServiceManagerクラスを使用するコンソールアプリ)を追加できる場合は、スタンドアロンの.exeを開始して、サービスを再起動して終了することができます。

考え直してみると、サービスにスケジュールされたタスクを登録して(たとえば、コマンドラインの 'at'コマンドを使用して)、サービスを開始してから停止させることができます。それはおそらくうまくいくでしょう。


3

バッチファイルまたはEXEへのシェルアウトの問題は、外部アプリを実行するために必要な権限がサービスにある場合とない場合があります。

私が見つけたこれを行う最もクリーンな方法は、サービスコントロールマネージャーのエントリポイントであるOnStop()メソッドを使用することです。その後、すべてのクリーンアップコードが実行され、停止コードが機能していると仮定すると、ハングしているソケットや他のプロセスはありません。

これを行うには、終了する前にフラグを設定して、OnStopメソッドにエラーコードで終了するように指示する必要があります。その後、SCMはサービスを再起動する必要があることを認識します。このフラグがないと、SCMから手動でサービスを停止できません。これは、エラー時に再起動するようにサービスを設定したことも前提としています。

これが私の停止コードです:

...

bool ABORT;

protected override void OnStop()
{
    Logger.log("Stopping service");
    WorkThreadRun = false;
    WorkThread.Join();
    Logger.stop();
    // if there was a problem, set an exit error code
    // so the service manager will restart this
    if(ABORT)Environment.Exit(1);
}

サービスで問題が発生し、再起動する必要がある場合は、SCMからサービスを停止するスレッドを起動します。これにより、サービスは自動的にクリーンアップできます。

...

if(NeedToRestart)
{
    ABORT = true;
    new Thread(RestartThread).Start();
}

void RestartThread()
{
    ServiceController sc = new ServiceController(ServiceName);
    try
    {
        sc.Stop();
    }
    catch (Exception) { }
}

2

Windowsスケジューラを使用して、サービスの再起動をスケジュールします。問題は、自分自身を再起動できないことですが、自分自身を停止することができます。(あなたは基本的に、座っているブランチを切り取ってしまいました...私の例えになられば)別のプロセスが必要です。Windowsスケジューラは適切なものです。1回限りのタスクをスケジュールして、サービスを(サービス自体の中からでも)再起動してすぐに実行します。

それ以外の場合は、それを行う「シェファーディング」プロセスを作成する必要があります。


2

質問への最初の応答は最も簡単な解決策です: "Environment.Exit(1)"私はこれをWindows Server 2008 R2で使用しており、完全に機能します。サービスは自動的に停止し、O / Sは1分間待機してから再起動します。


待機する時間は、待機するように設定した時間によって異なります。デフォルトは1分ですが、誰かがそれを望まない場合、あなたの答えは間違った印象を与えます。
エスペン2017年

1

できないと思います。サービスが「停止」すると、完全にアンロードされます。

ええと、わかりました、私が推測する方法は常にあります。たとえば、分離されたプロセスを作成してサービスを停止し、再起動して終了することができます。


0

より良い方法は、NTサービスをアプリケーションのラッパーとして利用することです。NTサービスが開始されると、アプリケーションは、コマンドが開始するのを待機する(または自動的に開始するように構成された)「アイドル」モードで開始できます。

車のことを考えてみてください。それが始まると、アイドル状態から始まり、コマンドが前進または後退するのを待ちます。これにより、アプリケーションの公開方法を選択できるため、リモート管理が向上するなど、他の利点も得られます。


0

ただ渡すだけで、私はいくつかの追加情報を追加すると思いました...

例外をスローすることもできます。これにより、Windowsサービスが自動的に閉じ、自動再起動オプションが起動します。これに関する唯一の問題は、PCに開発環境がある場合、JITが起動しようとすることです。デバッグY / Nを示すプロンプトが表示されます。「いいえ」と言って閉じます。その後、適切に再起動します。(JITのないPCでは、すべてが機能します)。このJITがWin 7で新しく(XPなどで正常に動作するため)、JITを無効にする方法を見つけようとしているのです。ここで言及されているEnvironment.Exitメソッドを試してみてください。それも機能します。

クリスチャン:ブリストル、イギリス


3
これらすべてが例外をスローし、exit(1)ソリューションはすべて、アプリケーションの適切なクリーンアップを回避します。
異常

0

このようなrestart.batファイルを作成します

@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%

次に、%service%の起動時にタスク%taskname%を削除します


0

アプリケーションコードをホストする別のappdomainを作成します。再起動が必要な場合は、プロセス(Windowsサービス)の代わりにappdomainをアンロードして再ロードできます。これがIISアプリプールの動作方法であり、asp.netアプリを直接実行せず、個別のappdmainを使用します。


-2

最も簡単な方法は、次のバッチファイルを作成することです。

ネットストップネットスタート

希望する時間間隔でファイルをスケジューラに追加します


バッチはサービス自体の子プロセスであるため、両方のコマンド間で停止されるため、機能しません。
Orabîg

-3
private static void  RestartService(string serviceName)
    {
        using (var controller = new ServiceController(serviceName))
        {
            controller.Stop();
            int counter = 0;
            while (controller.Status != ServiceControllerStatus.Stopped)
            {
                Thread.Sleep(100);
                controller.Refresh();
                counter++;
                if (counter > 1000)
                {
                    throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
                }
            }

            controller.Start();
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.