- PVSM.RU - https://www.pvsm.ru -
Ruby on RailsRedis (по причине например) Решение вопроса в сети пользователь или нет — это наверное как правило установка временной метки при обращении пользователя к приложению, а при необходимости узнать его (пользователя) текущий статус — сверка с этой временной меткой. Какой подход выбрать — решать Вам, но тот подход который предлагаю я — прост и не использует SQL базу данных, вместо этого используется Redis и одна из его встроенных возможностей — время жизни ключа (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" — использовать socket-подключение, если это возможноdriver: :hiredis — драйвер hiredis быстрееdb: 15 — использовать определённую базу данных, по умолчанию используется нулевая, но я рекомендую оставить её для тестирования, прикладных задач, чего нибудь другого. Нет проблем в использовании именно нулевой базы данных — суть в том, чтобы она была строго определена под онлайн-пользователей и больше ни для чего. # Gemfile
gem 'redis'
gem 'hiredis' # optional
Не забудьте запустить bundle
onlinecurrent_user скорее всего уже используется Вами — это тот метод, который возвращает текущего пользователя или nil — если пользователь не вошёл.
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
# обёртка в pipelined для ускорения, два запроса пойдут как один без ожидания
# ответа, использование multi-exec вместо pipelined
# не даёт такого прироста в производительности
$redis_onlines.pipelined do
# не нужно значение, нужен только ключ
$redis_onlines.set( current_user.id, nil )
# устанавливаем время жизни ключа - 10 минут, через 10 мину ключ удалиться
$redis_onlines.expire( current_user.id, 10*60 )
end
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
$redis_onlines.pipelined do
# вошедшему пользователю к ключу добавляем префикс "user:" перед id
$redis_onlines.set( "user:#{current_user.id}", nil )
$redis_onlines.expire( "user:#{current_user.id}", 10*60 )
end
else
$redis_onlines.pipelined do
# не вошедшему пользователю добавляем префикс "ip:" и записываем его id адрес
$redis_onlines.set( "ip:#{request.remote_ip}", nil )
$redis_onlines.expire( "ip:#{request.remote_ip}", 10*60 )
end
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 перед этим) и вот этот небольшой скрипт на ruby [2]. Для 9000 онлайн пользователей и 9000 онлайн анонимусов получилось так:
Аналогично для 65000 + 65000
Немножечко ссылок по теме (англ.):
pipelined [4]Автор: deep_orange
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/redis/57209
Ссылки в тексте:
[1] хостинга: https://www.reg.ru/?rlink=reflink-717
[2] небольшой скрипт на ruby: http://github.com/logrusorgru/any/blob/master/redis_onlines_db_size/test.rb
[3] Redis: http://redis.io/
[4] по поводу pipelined: http://redis.io/topics/pipelining
[5] set: http://redis.io/commands/set
[6] exists: http://redis.io/commands/exists
[7] expire: http://redis.io/commands/expire
[8] scan: http://redis.io/commands/scan
[9] scan_each: http://rdoc.info/github/redis/redis-rb/Redis#scan_each-instance_method
[10] redis-rb: https://github.com/redis/redis-rb
[11] неплохая статья для начинающих по Rails + Redis: http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
[12] Источник: http://habrahabr.ru/post/216047/
Нажмите здесь для печати.