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 風格配置文件中)。
    複製代碼

最後

只想告誡本身

有些坑只有踩過以後纔會記憶深入😭

相關文章
相關標籤/搜索