Ruby on Rails
Redis
(for the reason of hosting for example)SQL
database, instead Redis
used and one of its built-in capabilities is the key lifetime ( expire
). # config/initializers/redis.rb $redis_onlines = Redis.new
# config/initializers/redis.rb $redis_onlines = Redis.new path: "/tmp/redis.sock", db: 15, driver: :hiredis
path: "/tmp/redis.sock"
- use the socket
if possibledriver: :hiredis
- hiredis
driver fasterdb: 15
- use a specific database, the default is zero, but I recommend leaving it for testing, application tasks, something else. There are no problems in using the zero database - the point is that it was strictly defined for online users and for nothing else. # Gemfile gem 'redis' gem 'hiredis' # optional
bundle
online
current_user
method is most likely already used by you - this is the method that returns the current user or nil
- if the user is not logged in. def current_user @current_user ||= User.find_by_id( session[ :user_id ] ) end
# app/controllers/application_controller.rb after_filter :set_online # Rails 4 : # after_action :set_online # set_online private def set_online if !!current_user # , $redis_onlines.set( current_user.id, nil, ex: 10*60 ) # `ex: 10*60` - - 10 , 10 end end
# app/models/user.rb def online? # - false, true $redis_onlines.exists( self.id ) end
# app/cpntrollers/application_controller.rb def all_who_are_in_touch $redis_onlines.keys # => [ "123", "234", "1", "23" ] # id end
# app/controllers/application_controller.rb def set_online if !!current_user # "user:" id $redis_onlines.set( "user:#{current_user.id}", nil, ex: 10*60 ) else # "ip:" id $redis_onlines.set( "ip:#{request.remote_ip}", nil, ex: 10*60 ) end end
# app/models/user.rb def online? $redis_onlines.exists( "user:#{self.id}" ) end
# app/cpntrollers/application_controller.rb # ( id) def all_signed_in_in_touch ids = [] $redis_onlines.scan_each( match: 'user*' ){|u| ids << u.gsub("user:", "") } ids end # def all_anonymous_in_touch $redis_onlines.scan_each( match: 'ip*' ).to_a.size end # def all_who_are_in_touch $redis_onlines.dbsize end
FLUSHALL
before this) and this small ruby script . For 9000 online users and 9000 online Anonymus it turned out like this:pipelined
replaced by the use of the ex: timeout
option in the set
call. Thanks to printercu for the tip. A small test [ src: ruby ] showed a significant increase in performance.before_filter
instead of after_filter
- then the logged-in user will see himself on the list online during the first (in the next 10 minutes) visit. But then the choice depends on your needs / wishes. # app/cpntrollers/session_controller.rb # # - create # - destroy before_filter :clear_from_signed_in_touch, only: :destroy before_filter :clear_from_anonymous_in_touch, only: :create # ... private # - ip def clear_from_anonymous_in_touch $redis_onlines.del( "ip:#{request.remote_ip}" ) end # id - session[:user_id] # - id def clear_from_signed_in_touch $redis_onlines.del( "user:#{session[:user_id]}" ) end
Source: https://habr.com/ru/post/216047/
All Articles