보통 웹훅을 사용하기 위한 코드를 구현하고
웹훅을 받는 부분에 대해 생각을 해본적이 없을 것이다.
현재 회사에서 메신저를 담당하고 있고 웹훅 수신(webhook receiver)를 구현 할 수 있는 기회가 생겨서
얼마 전 (2022년 2월) 에 배포를 했고, 약 4개월 정도 하루에 1000개 정도의 웹훅을 수신 하고 있다.
Django 로 웹훅 수신 (webhook receiver) 부분을 구현했고 고민 했던 부분들을 기록에 남기려고 한다.
누군가에게 도움을 받거나, 방향성을 제시 받은 부분이 아니라 옳지 않은 방법 일 수도 있지만 나중에 다시 보았을 때
무엇을 고려하지 못했는지 깨달으면 더 좋을 것 같아서 남기는 것이 기록에 좋다고 생각했다.
1. 토큰
웹훅을 사용하면 보통 각자 고유의 토큰이 발급 된다.
Django auth token, Django jwt token 을 임의로 부분을 잘라 사용해서 인증을 하려고도 생각을 했었고,
다른방법으로 난수를 생성해서 database 에 넣고 인증 하려고도 생각했다.
구현 방법은 난수를 생성해서 database 에 넣고 클라이언트가 웹훅 수신쪽으로 POST 요청 할 때 인증을 한다.
난수 생성 방법은 python module secrets 을 import 해서 사용했다.
https://docs.python.org/ko/3/library/secrets.html
secrets.token_hex([nbytes=None])
limjian@Jians-MacBook-Pro-13 ~ % python3
Python 3.9.10 (v3.9.10:f2f3f53782, Jan 13 2022, 17:02:14)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import secrets
>>> secrets.token_hex(24)
'fab18d59cffd09ab7d8fa22d10fad18e4e9b0828d7788a38'
>>> secrets.token_hex(10)
'9fe2614c593bbcff1f20'
>>> secrets.token_hex(16)
'a54a07b48ca9ef881fa07173b3f3b104'
>>>
이런식으로 사용이 가능해서 클라이언트가 웹훅을 만들면 토큰을 바로 생성해 database 에 저장한다.
2. 수신 횟수 (ratelimit)
https://django-ratelimit.readthedocs.io/en/stable/
Django ratelimit module 을 사용해 구현을 했다.
ip 에 따라 초, 분 당 수신 횟수에 대한 제한을 걸 수 있었지만, 테스트를 많이 해봤는데 가끔 요청 횟수가 넘어 갈 때가 있기는 한 것 같다.
@ratelimit(key='ip', rate='60/m', method='POST')
def webhook():
pass
두번째로 생각한 방법은 nginx 에서도 ratelimt 이 있지 않을까 생각을 했고,
찾아보니까 많은 결과가 나왔지만 직접 사용해 보진 않았고, 현재는 django module ratelimit 을 사용중이다.
3. log
비 정상적으로 Post 요청이 많이 올 수 있는 상황을 대비 해서 ratelimt 을 사용했지만,
혹시 모를 상황에 log 를 syslog file 에 찍히도록 해놓았다.
logging module 을 사용했고
logging 을 사용해서 Django settings.py 설정, webhook receiver 함수 에서 log 를 찍는다.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': "[%(asctime)s.%(msecs)03d] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt': "%d/%b/%Y %H:%M:%S"},
'simple': {'format': '%(levelname)s %(message)s'},
},
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
'webhook': {
'level': 'DEBUG',
'class': 'logging.handlers.SysLogHandler',
'address': '/dev/log',
},
},
'loggers': {
'webhook': {
'handlers': ['webhook'],
'level': 'DEBUG',
'propagate': True,
},
}
}
비 정상적인 데이터 길이, 비 정상적인 데이터 형식 등 정말 많은 부분을 생각 했던 것 같다.
production 상태에서는 monitoring 툴 Sentry 도 사용을 하고 있는데
다행히 웹훅 수신 (webhook receiver)부분에서는 문제 발생이 되지 않는다.
웹훅 수신 (webhook receiver) 을 만든 이유는 고객이 요청해서 만들었고, 기한이 조금 촉박 했었지만
지금 그 요청한 고객들, 또 다른 고객들이 너무나 잘 사용하고 있어 만족감을 느낀다.
특히 같은 회사 개발자들에게도 편하다는 이야기를 종종 듣는다.
나중에.. 몇 달 뒤 구현해 놓은 코드를 다시 보면서, 더 생각해 봐야 될 부분과 문제점에 대해 생각을 해 봐야겠다.
(nginx ratelimit 에 대해서도 한번 해보고 알아 놓아야 할 듯)
'Framework > Django' 카테고리의 다른 글
[Django] redis.exceptions.AuthenticationError (Authentication required) (0) | 2022.10.12 |
---|---|
[Django] CORS (Cross-Origin Resource Sharing) (0) | 2022.07.16 |
[Django] models cached_property decorator (0) | 2022.02.23 |
[Django] models property decorator (@property) (0) | 2022.02.23 |
[Django] Ratelimit (django-ratelimit) (0) | 2022.02.17 |