4

updateコントローラーのアクションが呼び出されるたびに (またはモデルが更新されるたびに)、サーバー送信イベントを発行したいと考えています。私は現在watch、ダミーエミッターを使用して同じコントローラーで動作するアクションを持っています:

def watch
    self.response.headers["Content-Type"] = "text/event-stream"
    self.response.headers["Last-Modified"] = Time.now.ctime.to_json
    self.response_body = Enumerator.new do |y|
        100.times do |i|
            sleep 5
            y << ["event: message", "data: #{i}\n\n"].join("\n")
        end
    end
    # TODO catch IO error when client disconnects
end

updateが呼び出されたときに値を生成/返す列挙可能なオブジェクトを取得するにはどうすればよいですか? (注: 本当に Enumerable である必要はありませんが#each、このストリーミング手法が機能するには応答する必要があります。) ある意味では、Rails でイベント駆動型アーキテクチャを実装しようとしていると思います。

Observableは知っていますが、必要に応じてオブザーバーを列挙可能にする方法、またはループとスリープ タイマーを使用せずに (上記のように) オブザーバーを Enumerator に配置する方法がわかりません。

これの目的は、データベースに加えられた変更を、現在ログインしている他のすべてのユーザーに送信して、各ユーザーが常にデータベースの現在の反映を持つようにすることです。

ありがとう-

4

2 に答える 2

1

これは必ずしも最善の解決策ではありませんが、次のようにメッセージ キューを作成することになりました。データベースに新しいテーブル (「SSE」) を作成し、観察したいモデルにコールバックを追加しました。

class MyModel < ActiveRecord::Base
  after_save :queue_sse
  after_delete :queue_sse
  # ...
  private
    def queue_sse
      connected_users.each do |user|
        SSE.create(:changed_record_id => this.id, :user_id => user)
      end
    end
end

次に、watchアクションで:

def watch
  connected_users << current_user # pseudo for a mutex-synched accessor
  self.response.headers["Content-Type"] = "text/event-stream"
  self.response.headers["Last-Modified"] = Time.now.ctime.to_json
  self.response_body = Enumerator.new do |y|
    loop do
      sleep 5
      ActiveRecord::Base.uncached do
        updates = SSE.find_all_by_user_id(current_user)
        updates.each do |update|
          puts "update found: #{update.id}\n"
          y << ["event: message", "data: #{update.id}\n\n"].join("\n")
          update.destroy
        end
      end
    end
  end
  # TODO add error catching, and on IOError, remove the current_user
end

ただし、これはデータベースに多くの影響を与えます。おそらく、memcached、ミューテックス化されたクラス変数などで構築する必要があります。

(NB -- スレッド化が必要です。たとえばconfig.threadsafe!、もちろんスレッド化されたサーバーも必要です。)

于 2012-09-20T22:23:37.747 に答える
1

SSE を使用してイベントを「ブロードキャスト」できるようにする gem を作成しました。これにより、更新アクションから接続されたクライアントにデータをプッシュできます。それは R4S と呼ばれます ( https://github.com/biggihs/r4s )

def update
  #do some updating
  R4S.push_data("key",{data:"data"},:event=>"SomeJsEvent")     
end

これにより、sse ストリームの「キー」に接続されているすべてのブラウザにデータがプッシュされます。

于 2012-11-13T11:14:06.067 に答える