実現したいこと
Ruby on Rails(3.0.5)で出来たページにて、ボタン押下時に、別サーバにあるシェルスクリプトを非同期で実行したい(すぐ同じページにリダイレクトして操作できるようにしたい)です。
上記スクリプトは、cronで定時実行されているため、ボタン押下後、多重起動でスクリプトが実行できなかった時と、実行できた時に、それぞれ別のフラッシュメッセージを表示したいです。
ただし、そのスクリプトの処理は、別サーバとやりとりして、画像を加工するなど、かなり時間がかかる為、シェルスクリプトが起動できたかどうか判別できた後は、シェルスクリプトの完了を待たず、フラッシュメッセージを表示したいです。
→シェルスクリプトの起動ができたかどうかはRubyのcontroller側で受け取りたいが、その後は別サーバで勝手に処理を実行していて欲しいです。
試したこと
- スクリプト側で多重起動チェックを行うようにしました。
- 多重起動時は、標準出力に"already"という文字列を出力し、多重起動していなければ、本来スクリプトで実行される処理の前に、"success"という文字列を出力するようにしました。
- Open3.popen3を使用して、別サーバにあるシェルスクリプトを実行し、標準出力・エラーを随時受け取るようにしました。
- "success"または"already"という文字列を受け取ったら、ループを抜け、リダイレクトするようにしました。
発生している問題
"success"または"already"という文字列を受け取ったら、それに応じたフラッシュメッセージを表示して、リダイレクトできたのですが、"success"を受け取った後、スクリプトが動いているサーバにて、その後の処理が実行されていませんでした。
(該当のソースコード shのecho "success" >&1
以降の処理が実行されなかった)。
該当のソースコード
Ruby
1def push_button 2 3 Open3.popen3("ssh hoge bash huga.sh") do |stdin, stdout, stderr, wait_thr| 4 # 標準入力を閉じる。 5 stdin.close_write 6 7 begin 8 received_message = false 9 loop do 10 # .sh実行時のメッセージを受信したらループを抜ける 11 break if received_message 12 # 出力のメッセージを監視 13 IO.select([stdout, stderr]).flatten.compact.each do |io| 14 io.each do |line| 15 if line.include?("success") 16 flash[:success] = "バッチを実行しました。" 17 received_message = true 18 break 19 elsif line.include?("already") 20 flash[:already] = "バッチを実行できませんでした。時間をおいてから、再度お試し下さい。" 21 received_message = true 22 break 23 end 24 next if line.nil? || line.empty? 25 end 26 end 27 # 標準出力、標準エラーでEOFが検知された、つまり外部コマンドの実行が終了したらループを抜ける 28 break if stdout.eof? && stderr.eof? 29 end 30 rescue EOFError 31 end 32 33 redirect_to piyo 34end
sh
1#!/bin/sh 2 3# 二重起動チェック 4CMDLINE=$(cat /proc/$$/cmdline | xargs --null) 5if [[ $$ -ne $(pgrep -oxf "${CMDLINE}") ]]; then 6 echo "already" >&2 7 exit 9 8fi 9 10echo "success" >&1 11 12# やりたい本来のスクリプトの処理 13honsyori
現在の書き方だと、
- 本処理を実行する前にスクリプトの処理を中断してしまっている?
- そもそも非同期になっていない?
本件実現するための良い方法があれば、ご教示いただきたいです。
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー