最近负责公司的金融平台、其中在审核人员经过提现审核以后须要给用户发邮件进行通知。html
废话很少说、直接上代码:python
# coding: utf-8
import threading
import datetime
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email import encoders
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import os
import logging
logger = logging.getLogger('django')
class EmailSend(threading.Thread):
''' 发送邮件 '''
def __init__(self, msg, title, receivers):
self.msg = msg
self.title = title
self.receivers = receivers
self.img = os.path.join(os.path.abspath('.'), 'static/img/liveme.png')
threading.Thread.__init__(self)
def run(self):
EMAIL_LIST = self.receivers
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = '****'
EMAIL_HOST_PASSWORD = '****'
message = MIMEMultipart('related')
message['Subject'] = Header(self.title, 'utf-8')
msg_text = MIMEText(self.msg, 'html', 'utf-8')
message.attach(msg_text)
with open(self.img, 'rb') as f:
msg_image = MIMEImage(f.read())
msg_image.add_header('Content-Disposition', 'attachment', filename='liveme.png')
msg_image.add_header('Content-ID', '<0>')
msg_image.add_header('X-Attachment-Id', '0')
message.attach(msg_image)
logger.info('begin to send email, params: %s, time: %s' % (locals(), str(datetime.datetime.now())))
smtpObj = smtplib.SMTP()
smtpObj.connect(EMAIL_HOST, 25)
smtpObj.starttls()
smtpObj.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
smtpObj.sendmail(EMAIL_HOST_USER, EMAIL_LIST, message.as_string())
smtpObj.quit()
logger.info('end to send email, params: %s, time: %s' % (locals(), str(datetime.datetime.now())))
def send(msg, title, receivers):
''' 发送邮件 :param msg: :param title: :param receivers: :return: '''
EmailSend(msg, title, receivers).start()
复制代码
本地是用pycharm起的开发环境、OK、代码在本地彻底没问题、能够很好的把邮件发出去。可是把代码部署到测试环境的时候发现不行了(测试环境为uwsgi
)、TMD、邮件根本发不出去、也不报错。此刻表示很桑心😭。django
因而乎开始了漫长的排查过程。。。bash
测试服务器用的是aws,会不会是aws对服务器作了什么限制?服务器
开始找运维、通过运维同窗的一番折腾、发现aws没有作任何限制。不对啊、那为毛在本地就能够很好的发出去而到了aws就挂了、不科学啊。难道是网络缘由?因而又开始折腾搞网络的同窗、最后发现网络也没有问题😭网络
发现一个很怪异的问题:每次触发邮件操做以后都比如石沉大海似的没有了下文,可是一重启服务立马就能收到以前的邮件。多线程
这是什么逻辑,难道每次发完邮件都须要重启服务?显然不可能啊、没人这么干啊。算了,继续排查。app
排查中。。。运维
发现代码里面少了一个操做smtpObj.quit()
、恍然大悟、难不成不执行smtpObj.quit()
的话程序就会hang住?满怀期待的加上了这句代码、结果除了失望仍是失望😔。socket
继续排查。。。
这环境和代码都明明是如出一辙的、为啥啊、难道是多线程的问题?但是代码和环境都是同样的啊、想不通、开始走到崩溃的边缘。静下心来仔细想一想,不对、还有一个地方不同。本地开发环境是用python manage.py runserver
方式启动的、而测试环境是用uwsgi
方式启动的。因而抱着试试看的心态去Google了一下。TMD、还真是uwsgi搞的鬼、以前的uwsgi.ini配置以下:
[uwsgi]
socket=127.0.0.1:8000
#http= :8000
master=true
vhost=true
gid=nobody
uid=nobody
module=uwsgi
workers=24
max-requests=1000
limit-as=1024
pidfile=/data/app/cms-finance/uwsgi.pid
daemonize=/data/app/cms-finance/uwsgi.log
log-x-forwarded-for
harakiri=1800
buffer-size=16384
复制代码
后来增长了俩配置:
enable-threads=true
lazy=true
复制代码
再次触发邮件操做、万幸、此次可算是收到了。
官方文档是这么说明的
Python 线程小贴士
若是你没有使用线程启动 uWSGI,Python 的 GIL
将不会被开启,因此你的应用产生的线程
将永远不会运行。你可能不会喜欢这个选择,可是记住 uWSGI
是一个语言无关的服务器,因此它的大部分选择都是尽量维持它 “agnostic”。
可是不用担忧,基本上不存在不能经过选项来改变的由 uWSGI 开发者决定的选项。
若是你想维持 Python 的线程支持同时应用又不启动多个线程,只须要加上
--enable-threads 选项 (或者 enable-threads = true 在 ini 风格配置文件中)。
复制代码
最后
只想告诫本身
有些坑只有踩过以后才会记忆深入😭