なひです.

> From: Yukihiro Matsumoto
> Sent: Friday, February 26, 1999 3:16 PM

なひ:
> |> SIGPIPEの方は,ほっとくと / application.commitを通らないので,
> |> 溜めたデータがリセットされちゃいますよね...

松尾さん:
> |そうなんでしたっけ? SIGKILL(?)以外なら落ちるときでも 
> |httpserver.initialze の中の、ensureは通ると思ってました。スレッドが異
> |なると駄目なのかなぁ。本当はどうなんでしょう。教えてえらい人。

まつもと ゆきひろさん:
> ensureを実行するように作っているつもりだったんですが,通りま

ruby 1.2.3(99/02/16) [sparc-solaris2.5.1]を使っています.

簡単なサーバを作って試してみたんですが,
やはり親ブロックのensureに制御が移る前に
プロセスが死んでいるような気がします.

ENDブロックも書いてみましたが,やはり
trap( 'SIGPIPE', 'EXIT' )
しておかない限り実行されないようです(あたりまえか...

実際Meeting2000_0_92b1でも,
「新規会合登録」で登録を行なった後,
ブラウザのリロードボタンを押しっぱなし攻撃等で
サーバを落としてしまうと,
直近60秒の変更はDBに反映されません.

# なひがまたなにか勘違いしていないといいんですが...

試したのは以下のサーバです.
これを「ruby server.rb &」で起動しておいて,
コマンドラインからSIGPIPEを送る(Solaris 2.*ならkill -13 プロセス番号)と,
"die..."と表示されずに「Broken pipe   ruby server.rb」で戻ってきます.
Meeting2000だと,この
      p "die..."
に該当する部分が,
@application.commitに相当しますよね? > 松尾さん

# 「ここはこう書くのがRuby流」というコメントを歓迎します.(^_^;

--- 8< --- 8< ---: 以下はserver.rb

require 'SampleSvr.rb'
app = SampleSvr.new( 'localhost', 60080 )

--- 8< --- 8< ---: 以下はSampleSvr.rb

require 'thread'
require 'socket'

class SampleSvr

 private
  DefaultSvrHostName = 'localhost'
  DefaultSvrPortNo = 60001
  ReadBlockSize = 512
  WriteMessage =<<'EOM'
HTTP/1.1 200 OK
Content-type: text/plain

hello world!
EOM

  @svr
  @hostName
  @portNo

 private
  def initialize( hostName = DefaultSvrHostName, portNo = DefaultSvrPortNo )
    begin
      @hostName = hostName
      @portNo = portNo
      p "#{@hostName}##{@portNo}"
      run
    resuce
      p "rescued@initialize"
    ensure
      p "die..."
    end
  end

  def run
    @svr = TCPserver.open( @hostName, @portNo )
    while true
      begin
      	socket = @svr.accept
      rescue Errno::EPROTO
	p "Accept failed."
	next
      end
      #p "accepted"
      Thread.new { acceptHandler( socket ) }
    end
  end

  def acceptHandler( mySocket )
    begin
      mySocket.sysread( ReadBlockSize )	# dummy read
      mySocket.syswrite( WriteMessage )
    rescue Errno::ECONNRESET
      p "Connection reset by peer"
    rescue
      p $!
    ensure
      mySocket.close
    end
  end
end