V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
TANKING
V2EX  ›  程序员

有谁会开发微信模板消息推送队列的吗?

  •  
  •   TANKING · Mar 2, 2018 via iPhone · 8150 views
    This topic created in 2990 days ago, the information mentioned may be changed or developed.
    有谁会开发微信模板消息推送队列的吗?因为一次性推送到几千个用户,只能用消息队列,如果用 for 循环,遍历的方式,会造成 php 运行超时。
    41 replies    2018-03-03 15:59:58 +08:00
    SourceMan
        1
    SourceMan  
       Mar 2, 2018   ❤️ 1
    fkmc
        2
    fkmc  
       Mar 2, 2018
    ...有啥难的 简单点 一个线程从 redis 列表取数据 再推送就好了
    reexamine
        3
    reexamine  
       Mar 2, 2018
    送分题,典型的队列应用场景
    akafeng
        4
    akafeng  
       Mar 2, 2018
    为什么会使用 for 循环...
    dangyuluo
        5
    dangyuluo  
       Mar 2, 2018
    beanstalkd,rabbitMQ,太多了
    zonyitoo
        6
    zonyitoo  
       Mar 2, 2018
    居然想到的是用 for 循环…………………………醉
    TANKING
        7
    TANKING  
    OP
       Mar 2, 2018 via iPhone
    谁有一些例子可以看看?
    jswh
        8
    jswh  
       Mar 2, 2018
    这种都用不到那么重的队列,几千个用户......。你的 php 超时是因为在 fpm 里超时吧。你把用户取到之后写到一个文本文件里面,然后在 cli 下跑就好了。如果量不多,手动跑跑也行,或者就写个 cron 定时检查有没有需要跑推送的文件,记得开始推送了对这个文件打个锁标记避免重复推送就好了。
    odirus
        9
    odirus  
       Mar 2, 2018   ❤️ 1
    那啥啥啥,小项目,完全可以就地取材,MySQL 也可以很好地实现消息队列的。。。反正我们小项目都用 MySQL 做消息队列了,多一个组件,多一份危险;大项目再上 MQ,保证 MQ 的高可用性需要花很多精力的。

    假设数据表 tab_task 大致这样的:
    seq_id, is_active, create_time, update_time

    其中 is_active = 0 标示待消费的,is_active = 1 表示正在被处理,is_active = 2 标示已经处理好的。

    --------------------------------------------------
    正常消费线程,获取一个待处理任务(在一个事务中执行):

    UPDATE tab_task SET `is_active` = 1 AND `seq_id` = LAST_INSERT_ID(`seq_id`)
    WHERE AND `is_active` = 0
    ORDER BY `seq_id` ASC LIMIT 1;

    SELECT * FROM tab_task
    WHERE ROW_COUNT() > 0 AND `seq_id` = LAST_INSERT_ID();

    ----------------------------------------------------

    定期检查超时的任务,然后发送报警,获取一个超时的任务(假设超时时间为 5 分钟):

    SELECT * FROM tab_task
    WHERE is_active = 1 AND NOW() > DATE_ADD(`update_time`, INTERVAL 5 MINUTE)


    --------------------------------------------------
    odirus
        10
    odirus  
       Mar 2, 2018
    只要面向接口编程,以后把 MySQL 队列替换成 MQ 队列就很方便
    om6r5sqSGG9Magr0
        11
    om6r5sqSGG9Magr0  
       Mar 2, 2018
    用 php 脚本跑啊
    opengps
        12
    opengps  
       Mar 2, 2018
    for 循环不是不可以,但是得用独立的线程,控制避免 cpu 连续争用
    shuye00123
        13
    shuye00123  
       Mar 2, 2018
    为什么要用队列啊,放线程池去运行就好了
    qce7
        14
    qce7  
       Mar 2, 2018
    cli 执行就行了
    TANKING
        15
    TANKING  
    OP
       Mar 2, 2018 via iPhone
    @qce7 cli 执行就不会超时的吗?
    zjsxwc
        16
    zjsxwc  
       Mar 2, 2018
    cli 执行怎么会超时
    loveCoding
        17
    loveCoding  
       Mar 2, 2018
    直接放 redis 吧 ,效率高,不占内存
    alinwu05
        18
    alinwu05  
       Mar 2, 2018
    这样推送会被微信取消消息模板功能的!!
    jjww
        19
    jjww  
       Mar 2, 2018
    @odirus #9
    小项目用 Redis 的 Pub/Sub 或者 List 做消息队列更合适.
    对比你的 MySQL 解决方案, 看起来是引入了第三方组件, 其实降低了开发复杂度, 并且稳定性以及效率上提高了不少.

    消息的生产者和消费者是不同的进程, 在功能上是解耦的.另外建议对消息用 msgpack 处理一下, 生产者 pack 消费者 unpack.

    项目大的话建议用 RabbitMQ 等更成熟的解决方案.
    TANKING
        20
    TANKING  
    OP
       Mar 2, 2018 via iPhone
    经测试,用 cli 是可以,不会超时,但是我要做成一个网页版系统,只能用消息队列了。
    TANKING
        21
    TANKING  
    OP
       Mar 2, 2018 via iPhone
    @loveCoding 不太会用这个,看了看文档有点麻烦。
    odirus
        22
    odirus  
       Mar 2, 2018
    @jjww

    谢谢指教,不过我有不同意见:

    经过挖坑、填坑,我其实并不推荐 redis 来实现队列之类的,不确定性太多:
    1. 如果我要查询历史消费记录,还是需要存储到其他稳定可靠的介质里面
    2. 引入 redis 之后需要考虑维护其稳定性

    如果真的是要扩展,我愿意上成熟的方案:例如阿里云的消息队列(当然如果有专门的基础组件研发团队,这又另说)
    liuzhedash
        23
    liuzhedash  
       Mar 2, 2018
    lsvih
        24
    lsvih  
       Mar 2, 2018 via iPhone
    滥用模版推送会被封的,亲测
    KgM4gLtF0shViDH3
        25
    KgM4gLtF0shViDH3  
       Mar 2, 2018
    @TANKING #20 可以用 PHP 调用命令行啊,网页版的也能用的。
    zarte
        26
    zarte  
       Mar 2, 2018
    设置超时时间长点呗
    xsdhy
        27
    xsdhy  
       Mar 2, 2018 via Android
    如果是有偿技术支持,可以私聊我。
    puritania
        28
    puritania  
       Mar 2, 2018 via iPhone
    最简单的 curl_multi 并发发
    des
        29
    des  
       Mar 2, 2018 via Android
    fpm 有办法在超时断开连接继续跑的办法,只不过没法直接返回结果了

    或者尝试 workman 及 swoole ?
    wangbenjun5
        30
    wangbenjun5  
       Mar 2, 2018
    1.数据量不多用 for 循环也没啥大毛病,cli 下面执行脚本就行,用 php 函数 exec 调用脚本就行!
    2.使用消息队列,把所有需要发送的消息扔队列里面,然后消费端多开几个进程跑,相等于多线程!
    GreatHumorist
        31
    GreatHumorist  
       Mar 2, 2018   ❤️ 1
    简答复杂都可以,简单点你可以跑个 cli 死循环,一直读 redis,要在网页操作就往 redis 里抛任务就可以。不用 redis 用 mysql 也行啊,写进 mysql。需要注意的一点是两小时已更新 access_token。
    fcoolish
        32
    fcoolish  
       Mar 2, 2018
    没人会用 for 循环吧
    TANKING
        33
    TANKING  
    OP
       Mar 2, 2018 via iPhone
    @GreatHumorist Access_token 不存进数据库。
    vovov
        34
    vovov  
       Mar 3, 2018 via Android
    说点实际的,我是用的 laravel 队列,运行半年了模板消息没出过问题。
    iyaozhen
        35
    iyaozhen  
       Mar 3, 2018 via Android
    几千用户怕啥。cli 跑几万用户照样 for 循环
    TANKING
        36
    TANKING  
    OP
       Mar 3, 2018
    @iyaozhen cli 的确没问题,但是做成项目来用不可能天天跑 cli
    silencefent
        37
    silencefent  
       Mar 3, 2018
    redis 存,redis 取,写自动任务,每分钟执行一次 cli 取出列表,foreach 循环拆散了发信,错误了直接关闭
    iyaozhen
        38
    iyaozhen  
       Mar 3, 2018 via Android
    @TANKING 楼上也说了 php exec 执行 cli,这样也算异步了
    TANKING
        41
    TANKING  
    OP
       Mar 3, 2018
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1480 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 132ms · UTC 17:08 · PVG 01:08 · LAX 10:08 · JFK 13:08
    ♥ Do have faith in what you're doing.