我通过电子邮件使用django错误报告。它通常是一个非常有用的功能,除了现在我们有5分钟的数据库停机时间,我收到了2000封电子邮件。是否有任何中间件可以帮助我限制django每分钟发送的电子邮件数量?
答案 0 :(得分:12)
以Gattster的优秀答案为例,我基于django的内置缓存函数编写了一个简单的实现。
# -*- coding: utf-8 -*-
from django.utils.log import AdminEmailHandler
from django.core.cache import cache
class ThrottledAdminEmailHandler(AdminEmailHandler):
PERIOD_LENGTH_IN_SECONDS = 10
MAX_EMAILS_IN_PERIOD = 1
COUNTER_CACHE_KEY = "email_admins_counter"
def increment_counter(self):
try:
cache.incr(self.COUNTER_CACHE_KEY)
except ValueError:
cache.set(self.COUNTER_CACHE_KEY, 1, self.PERIOD_LENGTH_IN_SECONDS)
return cache.get(self.COUNTER_CACHE_KEY)
def emit(self, record):
try:
counter = self.increment_counter()
except Exception:
pass
else:
if counter > self.MAX_EMAILS_IN_PERIOD:
return
super(ThrottledAdminEmailHandler, self).emit(record)
并且Django 1.9中的日志记录配置也已更改,因此为了使此处理程序正常工作,您需要将日志记录配置为:
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'fully.qualified.path.to.handler.ThrottledAdminEmailHandler'
}
},
'loggers': {
'django': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
更改仅用于将记录器的名称从django.request
更改为django
。如果查看日志记录系统文档,可以通过实现logging filter以更清晰(?)的方式实现。
答案 1 :(得分:8)
通过执行以下操作,我将电子邮件限制为每分钟10次。这使用我安装独有的redis连接功能。我建议修改incr_counter函数以满足您的需求。为了安全起见,请使用直接redis或memcache连接,而不是任何django.cache包装器。
settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'error_email_limiter.handler.MyAdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
error_email_limiter / handlers.py
class MyAdminEmailHandler(AdminEmailHandler):
def incr_counter(self):
c = get_redis_connection()
key = self._redis_key()
res = c.incr(key)
c.expire(key, 300)
return res
def _redis_key(self):
return time.strftime('error_email_limiter:%Y-%m-%d_%H:%M',
datetime.datetime.now().timetuple())
def emit(self, record):
try:
ctr = self.incr_counter()
except Exception:
pass
else:
if ctr >= 10:
return
super(MyAdminEmailHandler, self).emit(record)
答案 2 :(得分:2)
一种选择是切换到ErrorStack之类的错误报告。我写了一个django app来使它很简单,可以集成到你的项目中。
答案 3 :(得分:1)
我认为数据库停机时间不是故意的,在这种情况下你可能应该把你的Django进程放到某种 maintenance mode 或者让它脱机?
否则,通常的邮件应用程序是django-mailer,这可能对您有所帮助,因为它将外发邮件存储在您的数据库中,因此会失败:)
如果您确实需要率限制,最好在您的MTA中这样做。这可能意味着能够关闭负责发送邮件的MTA流程或使用this patch for qmail to throttle incoming connections as a means of fighting spam
之类的异国情调的部分答案 4 :(得分:0)
可能Nagios' page关于拍打值得阅读