I am running into an issue using Channels where if two users are connected to the same socket, the consumer will run twice. When a single user is connected, only once.
So in practice: when I have two users chatting with each other over channels, a single sent message will be run through the consumer twice, causing it to save twice to the database. However, if there is only one participant in the channel, the message will run through the consumer once and save once as expected.
What might be the issue?
Here is the consumer:
-- So in practice: when I have two users chatting with each other over channels, a single sent message will be run through the consumer twice, causing it to save twice to the database. However, if there is only one participant in the channel, the message will run through the consumer once and save once as expected.
What might be the issue?
Here is the consumer:
class ChatConsumer(AsyncJsonWebsocketConsumer):
...
async def receive_json(self, content):
"""
Called when we get a text frame. Channels will JSON-decode the payload
for us and pass it as the first argument.
"""
# Messages will have a "command" key we can switch on
command = content.get("command", None)
recipient = content.get("recipient", None)
sender = self.scope["user"]
try:
if command == "join":
# Make them join the room
await self.join_room(content["room"])
previous_message_list = await get_saved_messages(recipient, sender)
for msg in previous_message_list:
await self.send_json({
"msg_type": MSG_TYPE_MESSAGE,
"room": content["room"],
"username": msg.sender.user.username,
"message": msg.message,
},)
elif command == "leave":
# Leave the room
await self.leave_room(content["room"])
elif command == "send":
await self.send_room(
content["room"],
content["message"],
content["recipient"]
)
except ClientError as e:
# Catch any errors and send it back
await self.send_json({"error": e.code})
...
async def send_room(self, room_id, message, recipient):
"""
Called by receive_json when someone sends a message to a room.
"""
# Check they are in this room
if room_id not in self.rooms:
raise ClientError("ROOM_ACCESS_DENIED")
# Get the room and send to the group about it
room = await get_room_or_error(room_id, self.scope["user"])
await self.channel_layer.group_send(
room.group_name,
{
"type": "chat.message",
"room_id": room_id,
"username": self.scope["user"].username,
"message": message,
"recipient": recipient,
}
)
...
async def chat_message(self, event):
"""
Called when someone has messaged our chat.
"""
# Send a message down to the client
# Save message object
await save_message_object(
sender=event["username"],
message=event["message"],
recipient=event["recipient"]
)
await self.send_json(
{
"msg_type": MSG_TYPE_MESSAGE,
"room": event["room_id"],
"username": event["username"],
"message": event["message"],
},
)
So something is causing the last function--def chat_message() to run twice and I think it's in the consumer and not related to the client because sent messages will log to the console only once--as soon as the messages are sent over socket.send, there will be two of the same Message objects saved onto the db.
Here is code relating to the actual save. It is in utils.py and is decorated using sync_to_async in order to call the sync func from an async consumer:
@database_sync_to_async def save_message_object(sender, message, recipient): recipient = Profile.objects.get(user__username=recipient) sender = Profile.objects.get(user__username=sender) m = Message(sender=sender, message=message, recipient=recipient) m.save() print(datetime.datetime.now())
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/1a8b04b5-088e-41bd-a0f1-53d326f5f8e9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
No comments:
Post a Comment