나는 APScheduler로 1시간마다 블랙리스트에 등록된 JWT중 기간이 만료된 토큰을 삭제하는 작업을 구현했다.
# sheduler.py
@transaction.atomic
def clean_expiry_token():
now_date = timezone.now()
expired_tokens = OutstandingToken.objects.filter(expires_at__lt= now_date)
print(f"기간 지난 refresh 토큰 수 => {len(expired_tokens)}")
if expired_tokens != 0:
for instance in expired_tokens:
token_id = instance.id
try:
blacklist_instance= BlacklistedToken.objects.get(id= token_id)
blacklist_instance.delete()
except:
pass
instance.delete()
그런데 Scheduler가 몇번은 문제없이 JOB이 실행되는데, 또 몇번은 "database is locked" 오류와 함께 정상적으로 실행되지 않고 있다.
안될꺼면 전부다 안되야지.. 어떤 경우엔 되고 어떤 경우에 안되고 하는지 확실히 모르겠다.
나는 database is locked 에 관한 문제를 Django 공식 문서에서 확인할 수 있었다.
내용을 요약해보면 다음과 같다.
장고의 기본 데이터베이스인 SQLite3는 경량 데이터베이스로 고수준의 Multi-thread를 지원할 수 없어 동시에 데이터베이스에 작업을 할 때, "database is lock" 오류가 발생한다.
즉, SQLite3의 한계로 인한 오류이다.
Django 공식 문서에서 제시하는 해결 방안은
Solution.1 - 경량 DB인 SQLite3 말고 다른 DB 사용하기.
Solution.2 - 동시성과 트랜젝션 줄이는 코드로 다시 작성.
Solution.3 - 기본 Timeout 시간을 늘리기.
나는 "database is locked" 문제를 근본적으로 해결하기 위해서는
경량 DB인 SQLite3 말고 고수준의 동시성을 지원하는 MySQL이나 PostgreSQL을 사용하는게 좋을 것 같다는 생각이 들었다.
그래서, 데이터베이스를 PostgreSQL로 변경하고 오류를 해결했다.
데이터베이스 자체를 바꾸고 난 뒤, 정상적으로 작동하고 있다!
psycopg2
라이브러리 설치$ pip install pycopg2
$ psql postgres
# 새로운 DB(pg_db) 생성
postgres=# create database pg_db;
# pg_db 와 연결
postgres=# \connect pg_db;
# 사용자 root_kim 생성 및 root_kim 비밀번호 password
project=# create user root_kim with password 'password';
# utf-8 인코딩
project=# alter role root_kim set client_encoding to 'utf-8';
# 시간대 설정
project=# alter role root_kim set timezone to 'Asia/Seoul';
# root_kim 권한 부여
project=# grant all privileges on database pg_db to root_kim;
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'pg_db',
'USER': 'root_kim',
'PASSWORD': 'password',
'HOST': '127.0.0.1', # default
'PORT': '5432', # default
}
}
https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors
https://velog.io/@chaeri93/Django-Django와-Postgresql-연동하기