※ 기본 소스코드는 Django channel tutorial 소스입니다.
장고에서 Asynchronous(Async) 를 이용한다면, request 에 대한 response 를 기다리지 않고 작업을 처리한다.
따라서 비동기를 이용하면 실시간 데이터를 주고 받는 chat-server, 주식사이트 와 같은 곳에서 이점을 가진다.
하지만 Websocket server 에서 종종 데이터베이스 조회를 해야 하는 작업이 필요해질 때가 있다.
예를 들어, 채팅 서버에서 채팅방 또는 이전 채팅내역을 가져와야 하는 상황이 온다면 DB를 조회해야 한다.
이때, DB 내 저장된 데이터를 가져오기 위해서는 ORM 또는 Query 문을 사용해야 하는데, 이렇게 된다면 데이터를 조회(request)하고 그에 대한 응답(response)까지 기다려야 해서 비동기적으로 처리할 수 없게 된다(병목현상).
그렇다면 어떻게 해야할까?
database_sync_to_async
과 같은 도구를 사용해서 데이터베이스 조회를 비동기로 처리하면 된다.
먼저 비동기 방식을 제대로 고려하지 못한 코드부터 알아보자.
# consumers.py
class ChatConsumer(AsyncWebsocketConsumer):
# ...
def saveDB(self, msg, user_name, room_name):
from chat.models import ChannelDATA
ChannelDATA.objects.create(user_name= user_name, messages= msg, room_name= room_name)
# Receive message from WebSocket
async def receive(self, text_data):
# ...
await self.saveDB(message, user_name, self.room_name)
# ...
위와 같이 구현했다면 ORM 을 통해 데이터베이스에 저장될 때, 동기(Sync)으로 처리되어 오류가 발생하게 된다.
오류 코드를 보면, use a thread or sync to async
즉, 쓰레드 모듈을 사용하거나 sync(동기) 작업을 async(비동기) 작업으로 변경하라고 한다.
이제, 데이터베이스 작업을 비동기로 수행하기 위해 database_sync_to_async
를 사용해보자.
# consumers.py
from channels.db import database_sync_to_async
class ChatConsumer(AsyncWebsocketConsumer):
# ...
@database_sync_to_async
def saveDB(self, msg, user_name, room_name):
from chat.models import ChannelDATA
ChannelDATA.objects.create(user_name= user_name, messages= msg, room_name= room_name)
# Receive message from WebSocket
async def receive(self, text_data):
# ...
await self.saveDB(message, user_name, self.room_name)
# ...
database_sync_to_async
데코레이터를 사용하여 saveDB
함수를 동기에서 비동기로 변경해주었다.
이제, DB 안에 채팅 기록이 저장되는지 확인해보자!
데이터베이스 안에 정상적으로 저장되는 것을 볼 수 있다.