faye + redisを使用してサイトにログインしているユーザーを見つける別の方法

問題


Ruby on Railsを使用したアプリケーションと、gemの標準セット(deviseなど)がありました。 いずれかのページで、現在アクティブなユーザーに関する情報を表示する必要がありました。

解決策


最初の考えは、各リクエストで現在のユーザーにこのリクエストの時間を記録することでした。したがって、セッションのタイムアウトを知って、誰がアクティブで誰がアクティブでないかを計算することができました。 ただし、タイムアウトは約15分でした。そのため、タブを閉じたばかりの場合、この時間中もタブは「アクティブ」のままです。 セッションのタイムアウトを減らすことは不可能でした。 はい。また、約2kのアクティブユーザーが同時に存在することを考えると、データベースのレコードを毎回更新するオプションは少し残酷に見えました。 最も簡単で簡単なオプション-Webソケット+ redisを使用した実装。

フェイvs WebsocketRails


tldr; その結果、フェイが選ばれました。

最初の選択は2つの方法で提供されました。 良くなかった質問への答えをグーグルで探して、すべての長所と短所をドックと記事から掘り下げました。

websocket-railsには何の利点もありませんでしたが、マイナス面は明白でした。最後の更新はかなり前のことで、接続ごとに個別のストリームが開かれました。 次に、フェイはイベントマシンを介して動作し、完全に非同期であることに加えて、常に更新されます。

設置


Gemfile:

gem "hiredis", "~> 0.4.0" gem 'redis' gem 'faye' gem 'faye-rails' 


カスタマイズ


redisへの接続の初期化がinitializers / redis.rbに追加されました:

 Redis.current = Redis.new(host: 'localhost', port: 6379, driver: :hiredis) 

application.rb

 config.middleware.delete Rack::Lock config.middleware.use FayeRails::Middleware, mount: '/faye', timeout: 25 do map '/active_users' => ActiveUsersController add_extension(Inc.new) end 


この部分では、fayeはurl '/ faye'を介して接続されており、タイムアウトが示されていますが、これはこの問題を解決する上で非常に重要でした。 また、チャネルを特定のハンドラーにマッピングします。私の場合はActiveUsersControllerでした。 また、fayeの拡張機能が追加されました。 そのコードは次のようになります。

 class Inc def incoming(message, _request, callback) if message["channel"] == "/active_users" OnlineUsers.new(message["data"]["id"], message["clientId"]).online! end callback.call(message) end end 

これにより、「/ faye」にリクエストを送信した人を見つける機会が与えられました。 OnlineUsers内では、ユーザーのidとclient_ud(接続時にfayeによって発行される)をハッシュ内の大根に追加するだけでした。

 redis.hset(HASH_KEY, client_id, user_id) 


ハッシュキーだけですべてのアクティブを取得できます。

また、コントローラーでは、「サブスクリプション解除」イベントモニターを作成しました。理論的には、タブが閉じたときにトリガーされるはずでしたが、実際にはそれは毎回機能していました。 また、ユーザーがログアウトをクリックし、クリックによってクライアントが大根から削除された後、タイムアウト後にクライアントから何も聞こえない場合にも機能しました。

 channel '/channel_name' do monitor :unsubscribe do remove_online_user(client_id) end end 

前面には簡単なスクリプトがありました。

 client = new Faye.Client('/faye'); client.subscribe("/active_users", function(message){}) client.publish('/active_users', {id: user_id}); client.disable('autodisconnect'); 

faye用に別のシンサーバーが作成され、fayeがブロードキャストしているポートのみをリッスンしました。 したがって、30秒のデルタでオンラインユーザーを監視できることが判明しました。

その結果、すべてのオンラインユーザーのIDリストを取得するだけで十分です。

 redis.hgetall(HASH_KEY).values.uniq 

Source: https://habr.com/ru/post/J256471/


All Articles