Python中如何实现定时给达到条件的用户发送短信功能

以前接到一个需求,定时给注册一半的用户发送短信,我设计的实现方法是先把用户在 redis 中缓存,之后设置一个过期时间,然后每半小时检索一次对达成条件的用户进行短信发送,然后最近随手点开一个 app,人家的短信推送竟然能精确到分钟,我如果也把 redis 缓存做成分钟缓存,每一分钟执行一次感觉对服务器压力很大,如果不是用定时任务一分钟检索一次去发送短信的话还有哪种方法能达到优化的效果?
求大神指点~!
Python中如何实现定时给达到条件的用户发送短信功能

17 回复

要搞成那种 reactive 模式的


用Celery配合APScheduler或者直接用Celery Beat就能搞定。下面给你个完整的例子,用Django + Celery + Redis。

首先,安装依赖:

pip install django celery redis django-celery-beat

1. 配置Celery

在Django项目的your_project/celery.py中:

import os
from celery import Celery
from celery.schedules import crontab

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')

app = Celery('your_project')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# 定时任务配置
app.conf.beat_schedule = {
    'send-sms-every-minute': {
        'task': 'your_app.tasks.send_sms_to_eligible_users',
        'schedule': crontab(minute='*/1'),  # 每分钟执行一次
    },
}

2. 创建任务

your_app/tasks.py中:

from celery import shared_task
from django.contrib.auth.models import User
from datetime import datetime, timedelta

@shared_task
def send_sms_to_eligible_users():
    # 定义条件:例如,注册超过24小时但未激活的用户
    cutoff_time = datetime.now() - timedelta(hours=24)
    
    eligible_users = User.objects.filter(
        date_joined__lt=cutoff_time,
        is_active=False
    )
    
    for user in eligible_users:
        # 这里调用你的短信发送接口
        send_sms(user.phone, "您的账户需要激活")
        print(f"已发送短信给 {user.username}")

3. 启动服务

开三个终端分别运行:

# 启动Redis
redis-server

# 启动Celery worker
celery -A your_project worker --loglevel=info

# 启动Celery beat(定时任务调度器)
celery -A your_project beat --loglevel=info

4. 短信发送函数示例

简单实现个发送函数:

import requests

def send_sms(phone_number, message):
    # 这里替换成你的短信服务商API
    url = "https://your-sms-api.com/send"
    data = {
        "phone": phone_number,
        "message": message,
        "api_key": "your_api_key"
    }
    response = requests.post(url, data=data)
    return response.status_code == 200

关键点:

  • 用Celery处理异步任务,避免阻塞主程序
  • Celery Beat负责定时触发
  • 条件查询写在任务函数里,根据业务需求调整
  • 生产环境记得配置结果后端和监控

这样就能定时扫描数据库,给符合条件的用户发短信了。根据实际需求调整查询条件和发送频率就行。

总结:用Celery + Beat实现定时任务,在任务函数里写条件查询和短信发送逻辑。

用数据库的触发器可以做到实时发送



谢谢,等我研究一下这俩种方法

触发一个延迟任务,任务检查用户操作进度,根据条件执行业务逻辑。

mq,延迟消息

用 php 写一个小脚本就可以
写了一个简单的例子给你: https://github.com/kasuganosoras/SomeCodes/blob/master/v2ex_526598.php
具体的你自己改一下就可以了

对服务器压力很大 亮了
也许 99.9% 的定时任务回调对服务器一点影响没有也说不一定呢

如果你的每天注册的用户是海量的。。会发现这是矛盾的。。因为那时候,可能并不会用一个任务通过一次来处理所有的数据

先让任务使劲搞,后面如果服务器确实因为这个任务产生了影响,那就再想办法呗,干嘛提前优化?

有要求一分钟之内全发完吗? 弄个队列,让它慢慢发去不就好了,除非你的用户真的是很多…… 那样的话就不要想着用一个计划任务,或者一次处理就弄好呢

1 分钟对 redis 不会有太大的影响,一分钟做个一个 set。正经的途径是做个时间轮。

我是写 python 的,我自己的脚本把 1 小时改成 1 分钟就可以了,不过仍然谢谢

嗯 可能是我杞人忧天吧, 我很不要脸的表示 除了定时任务脚本我写的 发短信都不是我写的, 那短信接口用 TM 同步,都神逻辑,因此我怕对服务器压力大,我不过顺口提了一嘴,人家不改我也没办法,另外说一下 我们用的是 django,要是用 tornado 用同步我就忍了…

延时任务总是查单个用户,感觉还不如一分钟查一下把符合条件的都拽出来呢,查询的次数更少,性价比更高呢

谢了 时间轮是个不错的想法

这种一般是定时执行的,比如每天早上 10 点

让 key 的维度是分钟粒度的, 然后每分钟去轮询.

压力不会大的, 相信我.

数据库锁的粒度不同。

回到顶部