2014年10月7日火曜日

Hubotスクリプトでやけに長時間の処理をさせてしまうとその間経過報告ができなさげ

WinSCPを、
(1) Hubot→win32ole→WinSCP .NET AssemblyのCOMライブラリ→WinSCP .NET Assembly→WinSCPによって操作する
のでなく、
(2) Hubotのchild_process.spawn→winscp.exe /command "get ~~~" "exit"によって操作する
ことを検討している。

(1)の操作法で今まで開発してきたが、無理があることがわかった:

  • JScript用の方法でWinSCPイベントのリッスンを試みたが、反応なし。WSHでなくnode.js上だからだろう。
  • OLEコレクションをゲットできない。win32oleに未実装なため。
  • WinSCP操作(ダウンロード等)が終わるまでHubotスクリプトが終われない。Hubotイベントを発しても、実験の結果、リスナが発動されるのはスクリプトが終わった後になっているようなので、経過報告ができない。操作開始前にイベントフックしてリスナでsetInterval()してコールバックでプログレス出力させ、操作終了後にイベントフックしてリスナでclearInterval()してみたが、なんも出力されない。たぶん上記のようなわけで、インターバル設定が活きてる時間がゼロ時間みたくなってしまうのだろう。この実験結果から見るかぎりは、リスナは別.coffeeにいさせとけば並行して動いてくれるだろうというのは僕の思い込みだったように思われる。


(2)の方法は、WinSCPでのダウンロードや、Explzhでの解凍など、動作が長時間ならば、child_process.spawnでdetachedオプションを設定してWinSCPにコマンドラインでダウンロードを命じたあとchild.unref()。
これにより、親プロセスが child を待機することを防ぐことができる。
child_process.execFile・execではdetachedオプションがリファレンスに記載ない。

もちろん、(2)のWinSCPをコマンドラインで呼ぶ方法では、WinSCPイベントをリッスンして経過報告することはあいかわらずできない。
だが、刻々大きくなっていくはずの転送先ファイルサイズをHubotのインターバルで別途ポーリングするというF5アタック的な手が使えないわけではない。
お行儀よくやろうとすれば、WSHかC#で作ったプログラムを(2)の方法で呼び、そのプログラムからWinSCP .NET Assemblyをたたくほうがよいだろう。WSHだとCOM経由になって公式でもハックみたいになっちゃってるので、この際C#が正道ですね。

なお、ZIP解凍についても同様にspawnで
Explzh.exe /e "Archive file"
ZIP圧縮についても同様にspawnで7-Zipを働かせればよさげ。
※解凍も7-Zipのコマンドラインで解凍でもよいかもしれないが、いちおうExplzhは長い間使っていてファイル名文字化けなど生じてないという安心感があるので、乗り換えないほうが無難なような気がするので(7-Zipも、ファイル名文字化けは起こらないようよく工夫はされているようだが)。
※圧縮は、元のファイル名文字コードは必ず手元のWindowsなので不安はないし、7-Zipは同じ.zipを作るのでも圧縮率がより高い由。

一方、ファイルリスト取得など動作が短時間、かつ結果がほしいならば、child_process.execFileを用いればよいだろう。



↓今後の開発方針

(1)
Hubotから、
(a) filename・loginid・passwordなどから構築したURL
(b) チケットID
などをコマンドラインオプションとして、C#プログラムを呼ぶ。
具体的には、child_process.spawnでdetachedオプションを設定してC#プログラムを呼び出しchild.unref()。
これにより、親プロセスが child を待機することを防ぐことができる。

(2)
C#プログラムで、WinSCP .NET Assemblyにより、filenameがサーバ上に存在するかを確認。
存在しないなら
HubotにHTTPリクエストでNot foundと伝達してIRCに通知させ、
WinSCP .NET Assemblyでファイル一覧を取得し、
Redmine REST APIで所在フィールドにNot foundと書き込み、システムメッセージフィールドにファイル一覧を表示。
存在するなら
HubotにHTTPリクエストでダウンロード中と伝達してIRCに通知させ、
Redmine REST APIで所在フィールドにダウンロード中と書き込む。
WinSCP .NET Assemblyでダウンロード。
ダウンロード中は、WinSCP .NET Assemblyの進捗イベントのリスナがRedmine REST APIで経過報告用フィールド群に経過報告。
ダウンロード完了したら、HubotにHTTPリクエストでダウンロード完了と伝達してIRCに通知させ、
Redmine REST APIで所在フィールドにダウンロード完了と書き込む。



以上はげしくチラ裏

0 件のコメント:

コメントを投稿