uwsgi+django+gmail+threading多线程发邮件

uwsgi+django+gmail+threading多线程发邮件

最近负责公司的金融平台、其中在审核人员经过提现审核以后须要给用户发邮件进行通知。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

  1. 测试服务器用的是aws,会不会是aws对服务器作了什么限制?服务器

    开始找运维、通过运维同窗的一番折腾、发现aws没有作任何限制。不对啊、那为毛在本地就能够很好的发出去而到了aws就挂了、不科学啊。难道是网络缘由?因而又开始折腾搞网络的同窗、最后发现网络也没有问题😭网络

  2. 发现一个很怪异的问题:每次触发邮件操做以后都比如石沉大海似的没有了下文,可是一重启服务立马就能收到以前的邮件。多线程

    这是什么逻辑,难道每次发完邮件都须要重启服务?显然不可能啊、没人这么干啊。算了,继续排查。app

  3. 排查中。。。运维

    发现代码里面少了一个操做smtpObj.quit()、恍然大悟、难不成不执行smtpObj.quit()的话程序就会hang住?满怀期待的加上了这句代码、结果除了失望仍是失望😔。socket

  4. 继续排查。。。

    这环境和代码都明明是如出一辙的、为啥啊、难道是多线程的问题?但是代码和环境都是同样的啊、想不通、开始走到崩溃的边缘。静下心来仔细想一想,不对、还有一个地方不同。本地开发环境是用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 风格配置文件中)。
    复制代码

最后

只想告诫本身

有些坑只有踩过以后才会记忆深入😭

相关文章
相关标签/搜索