社内SEの徒然なる日記

powerShellを2重に起動できなくしたい

■ 要件

powerShellで作ったとある処理を、サーバーのログオン時に実行させています。
テスト段階では問題なく動作していたんですが、実運用を開始したところ、時々異常終了するようになりました。

原因を調べたところ、そのサーバーにリモートデスクトップで接続(ログイン)したせいで、powerShellの処理が2重起動したことが原因でした。

サーバーの遠隔操作ソフトはあるので、リモートデスクトップで接続しない運用にしても良いのですが、この手の運用ルールの追加は、大体ろくな結果にならない。

なんとか2重起動を防げないだろうか?

■ サンプル

ミューテックスという仕組みを利用すれば、2重起動を防げそうです。
10秒待機して終了するだけの単純な処理を作成して、そこにミューテックスを追加します。
Write-Output ('処理を開始します。   ' + (Get-Date -format yyyyMMdd_HHmmss)) 

# ミューテックスを作成します。
# 他ユーザーからの実行もあり得るので、「Global¥」を付けてグローバル・ミューテックスを利用します。

$mutexObject = New-Object System.Threading.Mutex($false, "Global¥MUTEX_TEST")

# シグナルを受信します。戻値がFalseの場合、処理を終了します。
# ※ Falseの場合、別のスレッドでミューテックスが作成されています。

if (-not $mutexObject.WaitOne(0, $false)) {
Write-Warning "既に処理が実行されています。"
Read-Host '何かキーを押すと、処理を終了します。'
exit
}

# 10秒待機します。
Start-Sleep -Seconds 10

# ミューテックスを解放します。
$mutexObject.ReleaseMutex()

# ミューテックスのリソースを解放します。
$mutexObject.Close()

# 終了メッセージ
Write-Output ('処理を終了します。   ' + (Get-Date -format yyyyMMdd_HHmmss))
exit

# -------------------------
# 前回の異常終了検出処理
# -------------------------

trap [System.Threading.AbandonedMutexException] {
Write-Warning "前回の処理で強制終了が発生しています。処理は続行されます。"
continue
}


解説

ミューテックスの使用方法の概要は、ミューテックスオブジェクトの作成、シグナル確認、ミューテックスオブジェクトの解放・廃棄になります。

1.ミューテックスオブジェクトの作成

New-Objectコマンドレットで、インスタンスを作成します。
作成するのは、System.Threading.Mutexクラス(.NET Frameworkのオブジェクト)。
コンストラクタの第一引数は、False固定、第二引数に適当な名前を付けときます。

この時に、先頭を「Global¥」とプレフィックスを付けることでシステム全体を対象とした2重起動の抑止が可能になります。要件が「リモートデスクトップでログインされた時の2重起動抑止」なので、これが無いときちんと動きませんでした。

2.シグナルを受信

WaitOneメソッドの戻値から、2重起動を検出します。
このメソッドの本来の役割は、「他のスレッドが使用している資産が解放されるまで待機する」で、戻値にTrueが返却された場合は、資産を使用できる状態になったということです。

第一引数は待機時間です、今回は待機する必要はないので0でOK。
第二引数は、マニュアル読んだんですけど、意味が分かりませんでした。
今回の用途では、Falseを設定しておけば良いようです。

このメソッドの戻値がFalseになる、ということは、既に処理が実行されているということですので、2重起動の警告メッセージを表示して処理を終了させます。

3.後始末

作成したミューテックスを解放します。
ReleaseMutexで解放、Closeで廃棄です。

このあたりは、オブジェクトを使用した時のお約束ですよね。

4.前回の異常の検出

powerShellが項番3の後始末をしない状態で終了された場合、次回の起動時にWaitOneメソッドで例外(AbandonedMutexException)が発生します。
十分にあり得る話なので、エラートラップを仕込んで、処理を続行できるようにしています。

■ 実験開始

まず、単独で実行してみます。
通常時は問題なく動作するようです。
Mutexi(正常)

では、前回異常時のエラートラップを実験してみます。
待機処理の実行中にCtrl + C で処理を終了させ、再度処理を実行します。
Mutexi(前回‘異常)

一見、上手く動作したように思えたのですが、思ったようには動いてくれませんでした。

例えば、powerShellの実行画面を2つ起動して、片方で処理を実行して途中で終了させます。
この状態で、もう一つの画面で同じ処理を実行したところ、前回異常時のエラーメッセージは表示されませんでした。

...なんでだろ?まぁ、前回異常時も処理を続行させるのが目的なので、ここでは目をつぶります。

最後に、本命の2重起動のチェックをしてみます。
画面を2つ同時に起動して、片方の画面で実行中に、もう片方でも実行します。
Mutexi(2‚重起動エラー)

うむ、2つ目の処理が動きませんね。これで行けそうです。

投稿記事の一覧:http://harikofu.web.fc2.com/

--- blog end ---
スポンサードリンク

PageTop

コメント


管理者にだけ表示を許可する