5

Thin/Unicorn はシングル スレッドであるため、Thread.current/per-request ストレージをどのように処理しますか?

簡単なテストを実行しただけです-あるセッションでキーを設定し、別のセッションから読み取ります-常に同じ場所から書き込み/読み取りを行うように見えます。ただし、WEBrickでは発生しません。

class TestController < ApplicationController
  def get
    render text: Thread.current[:xxx].inspect
  end

  def set
    Thread.current[:xxx] = 1

    render text: "SET to #{Thread.current[:xxx]}"
  end
end

config.threadsafe!application.rbに追加してみましたが、変化なし。

リクエストごとのデータを保存する正しい方法は何ですか?

ストレージに Thread.current を使用する gem (Rails 自体、tilt を含む) があるのはなぜですか? 彼らはこの問題をどのように克服しますか?

Thread.currentリクエストごとに安全である可能性がありますが、リクエスト後にクリアされず、自分でそれを行う必要がありますか?

  • Rails 3.2.9 でテスト済み

アップデート

以下の@skaleeと@JesseWolgamottとの議論と私の調査結果を要約すると--

Thread.current は、アプリが実行されているサーバーによって異なります。サーバーは同じ Thread.current で 2 つのリクエストが同時に実行されないようにする場合がありますが、このハッシュの値はリクエスト間でクリアされない可能性があるため、使用する場合は、最後の値を上書きするように初期値を設定する必要があります。

Rails、tilt、draper など、Thread.current を使用する有名な gem がいくつかあります。禁止されていたり、安全でない場合、彼らはそれを使用しないと思います。また、ハッシュでキーを使用する前にすべての値を設定しているようです (さらに、リクエストが終了した後に元の値に戻します)。

しかし全体として、Thread.current はリクエストごとのストレージのベスト プラクティスではありません。ほとんどの場合、より良い設計で十分ですが、場合によっては を使用すると効果的envです。コントローラーだけでなく、ミドルウェアでも利用でき、アプリ内の任意の場所に注入できます。

更新 2 - 今のところ、draper は Thread.current を間違って使用しているようです。https://github.com/drapergem/draper/issues/390を参照してください。

Update 3 - ドレーパーのバグが修正されました。

4

3 に答える 3

0

Thread.current「スレッド グローバル」データを格納するために使用することには依然として注意が必要ですが、Rails でこれを行うためのおそらく正しいアプローチは、 Thread.currentRack ミドルウェアを使用してオブジェクトをクリアすることです。これを簡単に行うために、Steve Labnik がrequest_store gem を作成しました。gem のソース コードは非常に小さいので、一読することをお勧めします。

興味深い部分を以下に再掲します。

module RequestStore
  def self.store
    Thread.current[:request_store] ||= {}
  end

  def self.clear!
    Thread.current[:request_store] = {}
  end
end


module RequestStore
  class Middleware
    def initialize(app)
      @app = app
    end

    def call(env)
      RequestStore.clear!
      @app.call(env)
    end
  end
end

全体 Thread.currentをクリアすることは良い習慣ではないことに注意してください。request_store が基本的に行っていることは、アプリが Thread.current に隠しているキーを追跡し、リクエストが完了するとそれをクリアすることです。

于 2013-01-28T12:10:05.017 に答える
0

通常、セッションに何かを保存したいでしょう。本当に短命なものが必要な場合は、Rails の flashを参照してください。リクエストごとにクリアされます。スレッドに依存するメソッドは、異なる Web サーバーでは一貫して機能しません。

env別のオプションは、ハッシュを変更することです。

env['some_number'] = 5

ところで、Unicorn は単なるシングル スレッドではなく、フォークです。要求ごとに新しいプロセスが生成されます (恐ろしく聞こえますが、Linux ではかなり効率的です)。そのため、Unicorn で何かを設定すると、たとえグローバル変数であっても、別のリクエストには保持されません。

于 2012-12-11T22:10:58.387 に答える