Upgrade to Pro — share decks privately, control downloads, hide ads and more …

タイムアウトにご用心 / Timeout might break application state

Fumiaki MATSUSHIMA
October 10, 2021
2.5k

タイムアウトにご用心 / Timeout might break application state

https://kaigionrails.doorkeeper.jp/events/127339

Kaigi on Rails _2021_ new LT 発表資料

Fumiaki MATSUSHIMA

October 10, 2021
Tweet

Transcript

  1. User.where(name: "foo").not_deleted /users_count 1. リクエストがくる 2. not_deleted scope を組み立 て中にタイムアウトになる

    4. タイムアウトしたときにスタックされ ていた where が適用される /users?name=foo 3. 別のリクエストがくる User.where(name: "foo").not_deleted.count User.not_deleted.count
  2. class Stack def stack @stack ||= [] end def with(name)

    stack.push(name) yield stack ensure stack.pop end end stack = Stack.new stack.with('foo') do p stack.stack #=> ["foo"] stack.with('bar') do p stack.stack #=> ["foo", "bar"] end p stack.stack #=> ["foo"] end
  3. ここでタイムア ウトしても セーフ class Stack def stack @stack ||= []

    end def with(name) stack.push(name) yield stack ensure stack.pop end end
  4. ここでタイムア ウトすると pop されない class Stack def stack @stack ||=

    [] end def with(name) stack.push(name) yield stack ensure stack.pop end end
  5. Rails のバグ? - 違う - あらゆるタイミングで Thread#raise されること を考慮するのは厳しいので諦めている -

    https://github.com/rails/rails/pull/17607#issuecomme nt-70538060 - Scope 以外にも ensure で状態をリセットすると ころはタイムアウトで壊れる可能性有
  6. rack-timeout の罠 - rails new して書かれている Puma にはタイム アウト機構はなく、rack-timeout が事実上デファ

    クト - Heroku のチュートリアルでも紹介されていたり - デフォルト設定だとまさにやばいケースに該当 する
  7. rack-timeout の罠 - term_on_timeout: true にすれば、タイムアウト したら TERM で殺してくれる -

    これはデフォルトではない - Puma を Clustered mode で動かしていない場合、true にするとサーバが完全に死ぬ
  8. デフォルトやばいのでは? - 警告だけでも提案したが通らなかった - rack-timeout gem が歴史的に TERM するわけではな い

    - 危ないという説明も既にある (doc/risks.md) - Puma のデフォルトは Clustered mode じゃない
  9. 伝えたいこと - タイムアウトしたプロセスを再利用してはいけな い - Middleware っぽいところでやってると特に危ない - rack-timeout は

    term_on_timeout を必ず true に - 具体的な再現コードなどは https://zenn.dev/mtsmfm/articles/d55d739104e87c