2009-04-15 4 views
1

active_recordは、Windows上のシグナルプロセスに対して何が起こっているのですか(これはMacの同じバージョンでは見られません)。例えば:Ruby、windows、active_record、およびControl-C

require 'rubygems' 
trap("INT"){puts "interrupted"} 
puts __LINE__ 
sleep 5 
require 'active_record' 
trap("INT"){puts "interrupted again"} 
puts __LINE__ 
sleep 5 

私は上記のコード(ルビー1.8.6、1.3.1宝石、ActiveRecordの2.2.2を)実行すると、私が最初に睡眠中に好きなように私は、^ Cのように何度も打つことができますが、 activerecordが要求された後の最初の割り込みは、スクリプトを終了させます。上記の場合、トラップはまだ実行されますが、プログラムを続行できないだけです。通常。

トラップの2番目の呼び出しを削除しても、動作には影響しません。

実際の煩わしい点は、状況によってはトラップがまったく実行できないことです。これを行うことの全体的なポイントは、自分のコードを自分自身で消去して(データベース内のフットプリントを削除して、次の人が正常な状態になるようにすることです)、これが本当の問題です。たとえば、:

putsを見て^ Cを押すと、トラップはまったく実行されません。

active_recordが必要な場合のみ、この問題が発生します。回避策はありますか?私はこれがバグか何かの説明があるかどうかを知りたいと思うだろう。私が言ったように、私はこの問題をmac - repeated^Csの結果として、トラップprocを複数回実行することになります。これを行うための全体のポイントは、(データベースにその足跡を取り除く自身後にクリーンアップするために私のコードを取得することであることを考えると

おかげで...

+0

をそれはWindows版のRubyです。あなたのマシンに火をつけていないことを喜んでください(私は1.4でバグを修正したと思います)。 – Pesto

+0

ちょっと不思議ですが、コードの一部でRubyのInterrupt例外を救済するのではなく、SIGINTをキャッチする必要があるのはなぜですか?おそらく、あなたのコード内の任意の* SIGINT *をキャッチするのではなく、長時間実行しているプロセスだけにソリューションを絞り込むことで十分でしょう。 –

+0

トラップの呼び出しをさらにテストしたい場合は、http://www.ntecs.de/old-hp/s-direktnet/ruby/uguide18.htmlのように 'Process.kill" INT "、$$'を呼び出すことができます。 また、トラップの戻り値は実行された前のProcであるため、アクティブレコードがそれを変更しているかどうかを確認できます。それは私のマックでそうするようには思わない。 –

答えて

1

は...

はあなたを持っています?。この問題を再現しようとしたときにだけ、データベースのトランザクションを使用して、それは問題を解決するためにはるかに簡単な方法になりますように思えみなさ

+0

問題は、スクリプトが10〜60分間実行され、多数の読み取り/書き込みが行われることです。トランザクション化することはできません。 – Sniggerfardimungus

0

私は別のパターンを見ました:

秒までになるまでのUbuntu(ルビー1.8.6)で
puts "start" 
trap("INT") { puts "interrupted" } 
sleep 5 
puts "end" 

これは、

start 
interrupted 
interrupted 
(etc) 
interrupted 
end 

だから "中断" プリント含むCRTL-Cが押されるたびに生成されます。 Windowsの(またRubyの1.8.6)の下では、これが生成する:

start 
interrupted 
end 

すなわちそれは、 "中断" に一度、その後、終了します。

SIGINT Rubyを処理している間、スリープルーチンを終了して次のステートメントに進みます。私の推測(手を振る)は、これは何とかRubyがWindows上のネイティブスレッドの代わりに緑色のスレッドを使用しているためです。どんな専門家もここにチャイムしてください。

あなたはハンドラでsleepを再起動することで、Unix系のy動作をエミュレートできます。

puts "start" 
trap("INT") do 
    puts "interrupted" 
    sleep 5 
end 
sleep 5 
puts "end" 

残念ながら、これは、各時間SIGINTが捕獲されるタイマーをリセットしますので、いくつかのハッキング必要があります:ねえ

$interval = 5 
def go_to_sleep(secs) 
    $started = Time.now 
    sleep secs 
end 
trap("INT") do 
    puts "interrupted" 
    time_to_sleep = [0,$interval - (Time.now - $started)].max 
    if time_to_sleep > 0 
    sleep time_to_sleep 
    end 
end 
puts "one" 
go_to_sleep($interval) 
puts "two" 
go_to_sleep($interval) 
puts "three" 
go_to_sleep($interval) 
関連する問題