今まで何度か、PowerShell Cmdlet バイナリモジュール(C#でdllを記述し、Import-Module
で利用するCmdlet)について書いてきました。実際、Cmdletを実戦投入して運用していますが、実際に運用してみるとなかなかはまりどころが多いこともわかりました。何回かにわけて、実際にこうやって解決したという(ベストとは言えないけど)プラクティスを紹介したいと思います。
連載目次
- スレッド・Rx
- ロギング
- 例外処理
- 設定(Configファイル)
スレッド・Rx
いきなりスレッドなわけですが、これは以前下記の記事で紹介したものを修正したいからです。
このエントリでも触れましたが、PowerShell Cmdletは WriteObject
メソッドと WriteError
メソッドは、呼ばれたメソッド(たとえば、ProcessRecord
メソッド)と同じスレッドから実行する必要があります。という観点でみると、実は一つ漏れがあって例外処理時にエラーが発生するのです。
以前載せていたものでは、Rxの Subscribe
メソッドのonError の中で例外処理をしていましたが、このActionThrowTerminatingError
を実行していました。ThrowTerminatingError
は内部で WriteError
メソッドを実行しているのですが、これが呼び出し元スレッドとは別のスレッドで実行されてしまい、Cmdletが強制終了してしまいます。
というわけで例外処理も含めて、すべての WriteObject
メソッドと WriteError
メソッドをメソッドの呼び出しスレッドと同じスレッドで実行するように修正したのが以下のコードになります。
今回はRxを使ったサンプルになりましたが、 async/await
を使った場合やそのほかの別スレッドでの実行を行う処理も同様です。WriteObject
メソッドと WriteError
メソッドはメソッドの呼び出しスレッドと同じスレッドから呼びだすようにしないといけません。そして、SynchronizationContext.Current
がCmdletクラス内では null になっていることにも注意する必要があります。