비동기적으로 동작하게 Consumer 수정
Synchronous consumers은 어떤 특별한 코드 없이 Django models에 접근할 수 있는 등, regular synchronous I/O functions을 호출할 수 있기에 편리하다는 장점이 있다.
반면에, Asynchronous consumers은 request를 다룰 때, 추가적인 threads를 만들 필요가 없기에 higher level of performance를 제공한다.
ChatConsumer은 async-native libraries(Channels and the channel layer)만을 사용하고, synchronous Django models에 접근하지 않는다. 그렇기에, 특별한 문제없이 asynchronous하게 바꿀 수 있다!
물론, synchronous django models를 사용하더라도, 추가적인 utility를 사용해서 바꿀 수 있지만, performance면에서는 조금 떨어질 수 있다.
chat/consumers.py를 다음 코드로 바꿔보자.
import json
from channels.generic.websocket import AsyncWebsocketConsumer # 그냥 WebsocketConsumer가 아님
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self): # 그냥 def가 아님
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
# async_to_sync가 필요 없음(channel layer에서 method를 호출할 때)
await self.channel_layer.group_add( # I/O를 수행할 때 await을 통해 async func을 호출한다.
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
테스트를 해보자.
그전에!
Redis를 시작해야하는 것을 잊지 말자!
> python manage.py runserver
2개의 tab을 열고, 모두 http://127.0.0.1:8000/chat/lobby/ 에 들어가서 정상적으로 동작하는지 시험해보자.
이로써, chat server이 fully asynchronous 해졌다!