celery实现微信小程序推送消息 自动化检索

celery实现微信小程序推送消息 自动化检索

一、目录结构

使用如下目录结构:

目录结构

相关文件及说明:

celery.py 创建应用实例
config.py 参数配置文件
tasks.py 执行任务文件(消费者文件)

二、celery文件说明及介绍

celery是一个性能良好的python异步协调库 可以设置定时任务,协调请求方(生产者)与提供方(消费者)的库


我的另外一篇博客是关于celery入门使用理解处理机制

celery.py(创建app实例)

from __future__ import absolute_import
from celery import Celery

app = Celery('celery_proj', include=['celery_proj.tasks'])

app.config_from_object('celery_proj.config')

if __name__ == '__main__':
   app.start()

config.py(配置文件)

from __future__ import absolute_import
from datetime import timedelta

CELERY_RESULT_BACKEND = 'redis://:123456qw@@127.0.0.1:6379/6'
BROKER_URL = 'redis://:123456qw@@127.0.0.1:6379/5'
CELERY_TIMEZONE = 'Asia/Shanghai'


CELERYBEAT_SCHEDULE = {
   # 时钟周期为30 没30秒添加一次检索是否有需要推送消息的任务    
   'add-every-30-seconds': {
        'task': 'celery_proj.tasks.pullMsg', # 添加生产者函数
        'schedule': timedelta(seconds=30), #30秒后执行 建议和时钟同步
        'args': (60,)
   },
}

task.py(生产者函数)

from __future__ import absolute_import
import requests
from celery_proj.celery import app as ap # 由于后台使用的是flask框架 防止重复导入app
import sys
sys.path.append("..")
#调用封装好的redis数据库记录推送状态 已推送?未推送? 可以通过设置key的过期时间设置最小推送时间间隔
from model.redis_models import Redis_db 
from model.ord_models import *
import datetime

template_id = 'WJuAWZ1DGHzjcOk0W2BevWkZdORxITBNZE5gUfHEr9M'
app_id = 'wx64118b44bbd3bfa3'
secret_key = '微信小程序的密钥'


def get_access_token(app_id=app_id, secret_key=secret_key):
    ''' 获取微信access_token'''
    try:
        payload = {
            'grant_type': 'client_credential',
            'appid': app_id,
            'secret': secret_key
        }
        req = requests.get(
            'https://api.weixin.qq.com/cgi-bin/token',
            params=payload,
            timeout=3,
            verify=False)
        access_token = req.json().get('access_token', "")
        print('access_token', access_token)
        return access_token
    except Exception as e:
        print(e)


def push(
        openid,
        formId,
        item_info: dict,
        access_token,
        template_id=template_id):
    '''推送'''
    data = {
        "touser": openid,
        "template_id": template_id,
        "form_id": formId,
        'page': 'pages\person\myjoinedlist\myjoineditem_detail\myjoineditem_detail?wd={}'.format(
            item_info.get(
                'item_pass_id',
                '未知')),
        "data": {
            'keyword1': {
                'value': item_info.get(
                    'item_name',
                    '未知')},
            'keyword2': {
                'value': item_info.get(
                    'item_address',
                    '未知')},
            'keyword3': {
                'value': item_info.get(
                    'item_start_time',
                    '未知')}},
        "emphasis_keyword": ''}
    push_url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={}'.format(
        access_token)
    result = requests.post(push_url, json=data, timeout=3, verify=False)
    return result

@ap.task
def pullMsg(delta=60):
    '''推送消息'''
    access_token = get_access_token()
    now = datetime.datetime.now()
    timedel = datetime.datetime.now() + datetime.timedelta(minutes=delta)
    # 搜索所有快要开始的活动
    objlist = db.session.query(OrdObject.obj_id).filter(
        OrdObject.startOrd_time <= timedel,
        OrdObject.startOrd_time >= now)
    # 搜索相关订单
    ordlist = db.session.query(Orderinfo.ordNum).filter(
        Orderinfo.objId.in_(objlist)
    )
    # 查询可推送的用户和实例 此处为项目/活动
    # 搜索所有符合的用户,预定信息,项目名称,地址, 并且逐个推送
    # all (1, 'jhon', 'xixixi', 'bbbUI0egBJY1zhBYw2KhdUfwVJJE', datetime.datetime(2019, 5, 5, 14, 0))
    result = db.session.query(
        Item.item_id,
        Item.item_name,
        Item.item_address,
        Item.pass_id,
        Order.ord_usId,
        db.func.min(
            OrdObject.startOrd_time)).join(
        Orderinfo,
        Order.ord_num == Orderinfo.ordNum).outerjoin(OrdObject).filter(
                OrdObject.obj_id == Orderinfo.objId,
                OrdObject.startOrd_time <= timedel,
                OrdObject.startOrd_time <= now).group_by(
                    Item.item_id,
        Order.ord_usId).all()
    # 按状态推送 已推送的不推送
    status_db = Redis_db('pushMsg_status')
    formId_db = Redis_db('formId')
    if result and access_token:
        for i in result:
            item_id, openid = i[0], i[4]
            # 检查是否已推送
            response = status_db.check_pushMsg_status(item_id, openid)
            if response:
                # 已推送 下个
                continue
            else:

                # 未推送
                # 记录状态为已推送 假设未推送成功也最少24小时后再试
                response = status_db.set_pushMsg_status(item_id, openid)
                formId = formId_db.get_formId(openid)
                if formId:
                    # 推送 无法推送的情况,需要 改进redis过期时间
                    item_info = {
                        'item_name': i[1],
                        'item_address': i[2],
                        'item_pass_id': i[3],
                        'item_start_time': '{0}.{1}.{2} {3}:{4}'.format(
                            i[5].year,
                            i[5].month,
                            i[5].day,
                            i[5].hour,
                            i[5].minute)}
                    return push(openid, formId, item_info, access_token)
                else:
                    # 无法推送
                    return 'without formId!'
        return 'NO RESULT for!'
    else:
        return 'NO RESULT!'

三、通过守护进程启动

  • celery multi start w1 -A celery_proj -B -l info --logfile = celerylog.log (以守护进程启动 停止改成stop就行了 日志指定为celerylog.log)

你可能感兴趣的:(celery实现微信小程序推送消息 自动化检索)