Django - как отслеживать, если пользователь онлайн / оффлайн в режиме реального времени?
Я собираюсь использовать django-уведомления и веб-сокеты для отправки уведомлений в режиме реального времени в iOS/Android и веб-приложения. Поэтому я, вероятно, буду использовать Каналы Django.
могу ли я использовать Каналы Django отслеживать онлайн-статус пользователя в реальном времени? Если да, то как я могу добиться этого без постоянного опроса сервера?
Я ищу лучшую практику, так как я не смог найти ни одного подходящего решение.
обновление:
то, что я пробовал до сих пор, - это следующий подход:
Используя каналы Django, я реализовал потребитель WebSocket, который при подключении установит статус пользователя 'online'
, в то время как при отключении сокета статус пользователя будет установлен в 'offline'
.
Первоначально я хотел включить 'away'
статус, но мой подход не может предоставить такую информацию.
Кроме того, моя реализация не будет работать должным образом, когда пользователь использует приложение с нескольких устройств, потому что соединение может быть закрыто на устройстве, но все еще открыто на другом; статус будет установлен в 'offline'
даже если у пользователя есть другое открытое соединение.
class MyConsumer(AsyncConsumer):
async def websocket_connect(self, event):
# Called when a new websocket connection is established
print("connected", event)
user = self.scope['user']
self.update_user_status(user, 'online')
async def websocket_receive(self, event):
# Called when a message is received from the websocket
# Method NOT used
print("received", event)
async def websocket_disconnect(self, event):
# Called when a websocket is disconnected
print("disconnected", event)
user = self.scope['user']
self.update_user_status(user, 'offline')
@database_sync_to_async
def update_user_status(self, user, status):
"""
Updates the user `status.
`status` can be one of the following status: 'online', 'offline' or 'away'
"""
return UserProfile.objects.filter(pk=user.pk).update(status=status)
Примечание:
мое текущее рабочее решение использует платформу Django REST с конечной точкой API, чтобы клиентские приложения отправляли запрос HTTP POST с текущим статусом.
Например, веб-приложение отслеживает события мыши и постоянно публикует online
статус каждые X секунд, когда нет больше событий мыши опубликовать away
статус, когда вкладка / окно будет закрыта, приложение отправляет запрос POST со статусом offline
.
Это рабочее решение, в зависимости от браузера у меня есть проблемы при отправке offline
статус, но это работает.
то, что я ищу, - это лучшее решение, которое не нуждается в постоянном опросе сервера.
2 ответов
использование WebSockets, безусловно, лучший подход.
вместо того, чтобы иметь двоичный статус"online"/" offline", вы можете подсчитать соединения: когда новый WebSocket подключается, увеличьте счетчик" online " на один, когда WebSocket отключается, уменьшите его. Так что, когда это 0
, то пользователь находится в автономном режиме на всех устройствах.
что-то вроде этого
@database_sync_to_async
def update_user_incr(self, user):
UserProfile.objects.filter(pk=user.pk).update(online=F('online') + 1)
@database_sync_to_async
def update_user_decr(self, user):
UserProfile.objects.filter(pk=user.pk).update(online=F('online') - 1)
лучший подход-использование Websockets.
но я думаю, что вы должны хранить не только статус, но и сеансовый ключ или идентификация устройства. Если вы используете только счетчик, вы теряете ценную информацию, например, с какого устройства пользователь подключен в данный момент. Это ключевой момент в некоторых проектах. Кроме того, если что-то не так (отключение, сбои сервера и т. д.), Вы не сможете отслеживать какой счетчик связан с каждым устройством и, вероятно, вам нужно будет сбросить счетчик в конце.
Я рекомендую вам сохранить эту информацию в другой связанной таблице:
from django.db import models
from django.conf import settings
class ConnectionHistory(models.Model):
ONLINE = 'online'
OFFLINE = 'offline'
STATUS = (
(ONLINE, 'On-line'),
(OFFLINE, 'Off-line'),
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
device_id = models.CharField(max_lenght=100)
status = models.CharField(
max_lenght=10, choices=STATUS,
default=ONLINE
)
first_login = models.DatetimeField(auto_now_add=True)
last_echo = models.DatetimeField(auto_now=True)
class Meta:
unique_together = (("user", "device_id"),)
таким образом, у вас есть запись на устройство для отслеживания их статуса и, возможно, некоторую другую информацию, такую как ip-адрес, геопозиция и т. д. Затем вы можете сделать что-то вроде (на основе вашего кода):
@database_sync_to_async
def update_user_status(self, user, device_id, status):
return ConnectionHistory.objects.get_or_create(
user=user, device_id=device_id,
).update(status=status)
как получить идентификацию устройства
есть много библиотеки делают это как https://www.npmjs.com/package/device-uuid. Они просто используют набор параметров браузера для создания хэш-ключа. Это лучше, чем использовать только идентификатор сессии, потому что он меняется меньше frencuently.
отслеживание до статус
после каждого действие, вы можете просто обновить last_echo
. Таким образом, вы можете выяснить, кто связан или далеко и от чего устройство.
преимущество: в случае аварии, перезагрузки и т. д. Статус отслеживания может быть восстановлен в любое время.