项目案例—基于Celery、Redis和Flower的异步邮件报 警与监控

项目背景

异步任务队列的主要应用场景在:

  • 无须实现响应,性能占用较大,任务处理时间较长的任务,如占用网络性能的发送邮件,占用IO性能的视频处理。
  • 按时发布的定时任务,如定期对服务器的检查,对当天网站的监测分析。

Celery组件简介

Celery(芹菜)是一个Python编写的异步任务队列/基于分布式消息传递的作业队列。用于处理数以百万计的任务。

  • 三大组件: 消息中间件 (Broker),任务执行单元(Worker)和 任务执行结果存储(Backend)。
  • Celery支持RabbitMQ、Redis、ZoopKeeper等作为Broker,而对这些消息队列的抽象,都是通过Kombu实现的
    在这里插入图片描述
    Flower是基于web的 监控 和管理Celery的实时监控工具。
    Redis(Remote Dictionary Server)远程字典数据服务的缩写,由意大利人开发的是一款内存高速缓存数据库
    link

项目代码

项目所需安装的软件

$ pip install celery
$ pip install flower
#源码安装Redis软件(pip install -i https://pipy.douban.com/simple/ celery)

项目结构

celery/
├── config.py #项目配置文件:存储配置信息
├── main.py #主程序代码
└── tasks.py #异步要执行的任务程序:发送邮件,发送短信

项目代码

main.py

from celery import Celery # Celery用python编写的异步任务队列
# include指定任务存储文件的位置
app = Celery('app',include=['tasks']) # include=[要处理的任务]
# 加载配置文件
app.config_from_object('config')
if __name__ == '__main__':
    # 启动异步任务
    app.run()

# task.py

import time
from main import app

@app.task  # 通过装饰器把任务和celery队列绑定在一起,将任务存储在消息队列中,消息队列存储在redis中
def send_email(mail): #mail时以恶字典
    """模拟发送邮件,便于以后真实发送"""
    print('sending mail to %s.....' %(mail['to']))
    time.sleep(2)
    print('mail end')
    return 'send mail successful'
@app.task
def add(x,y):
    """模拟计算机函数"""
    print('add:%d+%d' %(x,y))
    time.sleep(0.5)
    return x+y

====

# config.py
from datetime import timedelta
from celery.schedules import crontab
# 使用Redis作为消息代理
BROKER_URL = 'redis://127.0.0.1:6379/3' # 将消息中间件存储在本地redis数据库中,执行任务是要把redis服务器先启动
# 使用Redis作为任务执行结果存储数据库,也可以是MySQL数据库
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/4'
# 任务序列化和反序列化格式为msgpack(类似json格式)  celery任务执行时的传输方式,‘msgpack’一种可移植的数据格式
CELERY_TASK_SERIALIZER = 'msgpack'
# 任务结果序列化存储格式为JSON(可读性更好)
CELERY_RESULT_SERIALIZER = 'json'
# 任务过期时间
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 #
CELERY_ACCEPT_CONTENT = ['json', 'msgpack'] # 任务接收内容的格式
# 设置时区
CELERY_TIMEZONE = 'Asia/Shanghai'

# 配置定时任务
CELERYBEAT_SCHEDULE = {
    'send-every-3-seconds': {
        # 执行的任务名称
        'task': 'tasks.send_email',
        # 定时任务设置(每隔5秒)
        'schedule': timedelta(seconds=5),
        # crontab定时任务(同Linux定时任务crontab配置)
        # 'schedule': crontab(hour=16, minute=30),
        'args':({'to':'hello@qq.com'},)
    },
    # 定时任务的名称
    'add-every-10-seconds':{
        'task':'tasks.add',
        'schedule':timedelta(seconds=10),
        'args':(1,2)
    }
}
  • 启动celery程序

celery -A tasks worker -B --loglevel=info # -A指定任务,-B显示高于info的日志信息
在这里插入图片描述
因为只是开启了celery队列,并没有产生任务,因此不会有执行结果

  • 交互式环境异步任务
    Celery 产生任务的方式有两种

    • 发布者发布任务
    • 任务调度按时发布定时任务

    $ ipython
    In [1]: from tasks import send_email
    In [2]: r = send_email.delay({‘to’:‘hello@qq.com’})
    In [3]: r.status
    Out[3]: ‘SUCCESS’
    In [5]: r.ready()
    Out[5]: True
    r.result # 查看任务执行的结果
    在这里插入图片描述
    在这里插入图片描述

  • 批量异步任务
    Celery 产生任务的方式有两种

    • 发布者发布任务
    • 任务调度按时发布定时任务
      方法一:在交互式界面中传递任务

import time
from tasks import send_email, add
#delay()用来调用任务, 返回任务执行结果
answer = send_email.delay(dict(to=‘windard@windard.com’))
while True:
print(‘wait for ready’)
#任务完成,跳出循环.
if answer.ready():
break
time.sleep(0.5)
print(answer.get())

方法二:在配置文件中进行配置定时任务
CELERYBEAT_SCHEDULE = {}
“”"
crontab方式


分钟 小时 日 月 星期
*/5 * * * * 每五分钟执行xxx
00 */2 * * * 每隔两小时执行xxx
00 12 */2 * * 每隔两天中午12点执行xxx
00 12 1 */2 * 每隔两个月1号执行xxx
00 23 * * 6 每周六晚上11点执行xxx
“”"

#定时任务的名称
CELERYBEAT_SCHEDULE = {
‘add-every-10-seconds’:{
‘task’:‘tasks.add’, # 要执行的任务
‘schedule’:timedelta(seconds=10), # 每10秒执行一次任务
# crontab定时任务(同Linux定时任务crontab配置)
# ‘schedule’: crontab(hour=16, minute=30),
‘args’:(1,2) # 要执行的任务需要传入的参数,以元组方式
},# 可以往后增加多个定时任务
}

Flower监控Celery

$ celery -A main flower --port=5556

访问网站: http://127.0.0.1:5556
在这里插入图片描述
在这里插入图片描述

邮件报警

邮件信息传递工作原理

  • SMTP协议: Simple Mail Transfer Protocol, 是一种提供可靠且有效的电子邮件传输的协议。SMTP建立在FTP文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。
  • POP3协议: Post Office Protocol - Version 3, 主要用于支持使用客户端远程管理在服务器上的电子邮件。
    在这里插入图片描述
    MIME是多功能Internet邮件扩展,设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。
    常见的MIME类型(通用型):
  • 超文本标记语言: .html text/html
  • xml文档 : .xml text/xml
  • PDF文档: .pdf application/pdf

不含附件邮件邮件报警代码

SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。
Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。

# 设置服务器,用户名、口令以及邮箱的后缀
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

smtp_server = "smtp.163.com"
from_username = '西部开源技术中心'
mail_user = "yw17392517656@163.com"
# 是开启smtp的授权吗不是真实的密码。
mail_password = "yw17392517656"
# 邮件主题的前缀
mail_prefix = "[运维开发部]-"


def send_email(to_addrs, subject, msg):
    try:
        # 将要发送的文本信息做MIME封装
        msg = MIMEText(msg)
        # 格式化发件人名称
        msg['From'] = formataddr([from_username, mail_user])# 发送者的信息
        msg['To'] = to_addrs # 接收者的信息
        msg['Subject'] = mail_prefix + subject

        # 1. 实例化smtp对象
        server = smtplib.SMTP()
        # 2. 连接邮件服务器
        server.connect(smtp_server)
        # 3. 登录
        server.login(mail_user, mail_password)
        # 4. 发送邮件内容
        server.sendmail(mail_user, to_addrs, msg.as_string())
        # 5. 关闭连接
        server.quit()
    except Exception as  e:
        print(str(e))
        return False
    else:
        return True
if __name__ == '__main__':
    send_email('741047561@qq.com','寒假作业', '请与2月2日之前提交')
    print("发送成功.....")

注意:用qq邮箱和163邮箱发送邮件有所不同,实例化smtp对象时要做如下的处理:
在这里插入图片描述

含附件邮件报警代码

# 设置服务器,用户名、口令以及邮箱的后缀
import os
import smtplib
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart  # 支持发送附件和正文信息
from email.utils import formataddr
# 设置服务器,用户名、口令以及邮箱的后缀
smtp_server = "smtp.163.com"
from_username = '西部开源技术中心'
mail_user = "yw17392517656@163.com"
# 是开启smtp的授权吗不是真实的密码。
mail_password = "yw17392517656"
# 邮件主题的前缀
mail_prefix = "[运维开发部]-"
def format_attach(file):
   """
  附件处理
  :param file: 文件对象
  :return:
  """
   filename = file.name  # 获取文件对象名称
   # 分割文本信息:分离文件名和后缀名并以元组方式返回  hello.png ==> ('hello','png')
   base, ext = os.path.splitext(filename)
   # 读取文件的时候必须知道类型是哪种扩展png、pdf
   # 通过MIMEApplication封装附件,需要知道拓展名
   attach = MIMEApplication(file.read(), _subtype=ext)
   # 封装的时候添加头部信息,告诉解释器这是附件信息
   attach.add_header('content-disposition', 'attachment', filename=filename)
   return attach # 返回封装好的附件
   
def send_email(to_addrs:str , subject:str, content:str, attaches:list=None)->bool:
	"""
  发送邮件
  :param to_addrs: 邮件接收人
  :param subject: 邮件标题
  :param content: 邮件正文内容
  :return bool
  """
    # 将要发送的文本信息做MIME封装  MIME是一种发送邮件的数据格式
    # msg = MIMEText(content)  # MIMEText将文本信息封装为MIME格式
    msg = MIMEMultipart(_subtype='alternative')
    # 格式化发件人名称
    msg['From'] = formataddr([from_username, mail_user])  # 把你的邮箱来一个别名
    msg['To'] = to_addrs
    msg['Subject'] = mail_prefix + subject
    msg.attach(MIMEText(content)) # 把报文和正文绑定在一起,将正文封装进报文里边
    # 把附件封装进报文
    if attaches:
        for attach in attaches: # 遍历每个附件
            if os.path.exists(attach): # 判断附件是否存在
                # 绑定在一起的不是附件的名称,而是附件的内容
                with open(attach,'rb') as f:
                # ‘rb’以二进制的方式去读取文件的内容因为文件可能是图片
                    result = f.read()
                    print(result)
                    msg.attach(format_attach(f))
            else:
                print('附件%s不存在' %(attach))
    try:
        # 1. 实例化smtp对象
        server = smtplib.SMTP()  # smtplib简单邮件协议的封装
        # 2. 连接邮件服务器
        server.connect(smtp_server)
        # 3. 登录
        server.login(mail_user, mail_password)
        # 4. 发送邮件内容
        server.sendmail(mail_user, to_addrs, msg.as_string()) # 将封装的信息转化成字符串发送出去
        # 5. 关闭连接
        server.quit()
    except Exception as  e:
        print(str(e))
        return False
    else:
        return True

if __name__ == '__main__':
    result = send_email('741047561@qq.com','寒假作业', '请与2月2日之前提交',attaches=['/etc/passwd'])
    if result:
        print("发送成功.....")
    else:
        print('发送失败')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值