Django-notifications とWebソケットを使用して、リアルタイム通知をiOS/AndroidアプリとWebアプリに送信することを検討しています。したがって、おそらくDjango Channelsを使用します。
Django Channelsを使用して、ユーザーのオンラインステータスをリアルタイムで追跡できますか?はいの場合、サーバーを定期的にポーリングせずにこれをどのように達成できますか?
適切な解決策を見つけることができなかったので、ベストプラクティスを探しています。
[〜#〜]更新[〜#〜]:
これまでに試みたのは次のアプローチです:Djangoチャネルを使用して、接続時にユーザーステータスを'online'
に設定するWebSocketコンシューマーを実装し、ソケットがユーザーステータスから切断されると'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)
[〜#〜]ノート[〜#〜]:
私の現在の作業ソリューションは、APIエンドポイントでDjango RESTフレームワークを使用して、クライアントアプリが現在のステータスでHTTP POSTリクエストを送信できるようにします。たとえば、Webアプリはマウスイベントを追跡し、マウスイベントがない場合は常にX秒ごとにPOST online
ステータスPOST away
ステータス。タブ/ウィンドウが閉じようとしているときに、アプリはPOSTリクエストをステータスoffline
で送信します。これはIS機能するソリューションであり、ブラウザによってはoffline
ステータスの送信時に問題が発生しますが、機能します。
私が探しているのは、常にサーバーをポーリングする必要がないより良いソリューションです。
WebSocketsを使用する方が間違いなく優れたアプローチです。
バイナリの「オンライン」/「オフライン」ステータスを使用する代わりに、接続をカウントすることができます。新しいWebSocketが接続するときに「オンライン」カウンターを1つ増やし、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)
最善のアプローチはWebsocketを使用することです。
ただし、ステータスだけでなく、セッションキーまたはデバイスID。カウンターのみを使用すると、たとえば、特定の瞬間にユーザーが接続しているデバイスなどの貴重な情報が失われます。これは、一部のプロジェクトでは重要です。さらに、何か問題が発生した場合(切断、サーバークラッシュなど)、各デバイスに関連するカウンターを追跡できなくなり、おそらく最後にカウンターをリセットする必要があります。
この情報を別の関連テーブルに保存することをお勧めします。
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 のように行うライブラリはたくさんあります。ブラウザーのパラメーターのバンドルを使用してハッシュキーを生成するだけです。変更の頻度が少ないため、セッションIDのみを使用するよりも優れています。
各アクションの後に、last_echo
を更新するだけです。このようにして、誰がどのデバイスに接続しているか、または離れているかを把握できます。
利点:クラッシュや再起動などの場合、追跡のステータスはいつでも再確立できます。