Python消息队列之Huey
缘起:
之前在Python中使用最多的就是Celery, 同样的在这次项目中使用了Celery+eventlet的方式,但是由于具体执行的逻辑是使用的异步编写的, 当时就出现了一个问题,当使用httpx的AsyncClient发送一个网络请求的时候, 发生了阻塞, 导致整个程序无法完整执行. 于是就找替代方案, 于是这次就尝试使用了huey,最终可以实现, 但是为何Celery中执行会发生阻塞,Google中也有大佬提到了
github: https://github.com/coleifer/huey
特点:
- 简单
- 轻量
- 执行多种类型: redis,sqlite,file,memory
安装:
pip install huey
# 将redis作为队列broker
pip install redis
使用:
-
配置Huey实例。
-
使用
@huey.task()
装饰器来标记要执行的任务。 -
在你的应用程序中调用该任务,它将被添加到任务队列中。
-
运行一个worker来监听队列并执行任务。
task.py
from huey import RedisHuey from redis import ConnectionPool redis_pool = ConnectionPool(host='127.0.0.1', port=6379, db=10, password="密码") huey = RedisHuey('app', connection_pool=redis_pool) @huey.task() def count_beans(num): for i in range(num): print(i) time.sleep(3) return 'count beans'
启动消费者:
huey_consumer task.huey -k process -w 4 # windows下 huey_consumer.exe task.huey -k process -w 4 # -k: 指定worker类型, thread(默认), greenlet, process(windows下不支持) # -w: 指定worker的数量, 同时有多少个消费者同时工作 # 还有其他的一些参数, 可以使用--help查看 # -l: 指定日志文件
# -v: 显示日志
主业务,将任务投递到队列中main.py
from task import count_beans if __name__ == '__main__': res = count_beans(10) print(res)
重试任务&定时任务
# tasks.py from huey import RedisHuey, crontab import logging import time # 配置huey实例 huey = RedisHuey('my_app', host='localhost') # 设置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # 一个简单的任务 @huey.task() def add_numbers(a, b): logger.info("Adding numbers: {} + {}".format(a, b)) return a + b # 带有失败重试的任务 @huey.task(retries=3, retry_delay=10) def flaky_task(): logger.info("Trying to perform a flaky task...") if random.choice([True, False]): raise ValueError("Oops! Something went wrong.") else: logger.info("Flaky task succeeded.") # 定时任务:每天执行 @huey.periodic_task(crontab(minute='0', hour='3')) def daily_task(): logger.info("Running daily task.") # 执行一些需要每天运行的操作 # 以下代码是模拟的任务使用案例,在实际应用程序中通常不会包含在任务定义的模块中 # 模拟任务队列和执行 if __name__ == '__main__': import random # 模拟添加任务到队列 for i in range(10): add_numbers(i, i*2) # 模拟执行任务队列中的任务 for _ in range(10): flaky_task() # 模拟定时任务的调用,实际情况下应该由huey的调度器执行 daily_task() # 这里我们模拟启动worker,实际上应当通过命令行启动 # 命令:`huey_consumer.py tasks.huey` # 以下代码将会启动一个循环,模拟worker的行为 while True: time.sleep(1) huey.flush()
注意点: 这里的定时任务,会使用自己的一个调度频率, 例如,每分钟执行, 并不是每分钟的0秒开始执行, 而是根据程序执行的时候,并且启动的时候会执行一次
整体使用感受,轻量,快速,清爽,还会有终端的时候,优雅处理方式
当然还有更多工具可以使用
Rq:
https://github.com/rq/rq
Mrq:
https://github.com/pricingassistant/mrq