61 lines
1.8 KiB
Python

"""Realtime synchronization for chat access changes.
The channel layer is an integration boundary: model signals publish only a
small access invalidation event, while the consumer owns group membership.
"""
from __future__ import annotations
import logging
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.db import transaction
logger = logging.getLogger(__name__)
def schedule_chat_access_changed(
*,
chat_id: int,
user_id: int,
membership_active: bool,
) -> None:
"""Notify every live session after the membership transaction commits."""
def _send() -> None:
channel_layer = get_channel_layer()
if channel_layer is None:
logger.warning(
"Chat access update skipped because channel layer is unavailable",
extra={
"event": "chat.realtime_access.channel_layer_unavailable",
"chat_id": chat_id,
"participant_id": user_id,
},
)
return
try:
async_to_sync(channel_layer.group_send)(
f"user_{user_id}",
{
"type": "chat_access_changed",
"chat_id": chat_id,
"membership_active": membership_active,
},
)
except Exception as error:
logger.exception(
"Chat access realtime update failed",
extra={
"event": "chat.realtime_access.send_failed",
"chat_id": chat_id,
"participant_id": user_id,
"membership_active": membership_active,
"error_type": type(error).__name__,
},
)
transaction.on_commit(_send)