我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户。

而我收到的用户需求也越来越多,产品化的需求,个性化的需求都有。这段时间收到一个海外 APP 的对接需求,需要我将客服系统的消息以队列的形式转发到对方的业务服务器上。

对方有两个核心需求:

  • 访客上线的时候,要通知对方的业务系统,业务系统根据访客的身份信息,推送个性化的欢迎词。
  • 访客完成下单的时候,要能推送一个下单成功的通知,并且包含订单信息和链接。

根据这两个需求,那就需要实现由客服系统到业务系统的消息队列推送,以及通过 Open Api 开放接口,以队列的形式接收对方业务系统的消息。


什么是消息队列,以及使用消息队列的好处这些基础知识,这里就不再赘述,本文重点讲一讲如何用 python 实现一个消息队列。

要用 Python 实现一个消息队列,你可以使用内置的 queue 模块来创建一个简单的队列,或者使用第三方库如 RabbitMQRedis 或者 Kafka 来实现更复杂的分布式消息队列。

如何通过 python 实现消息队列

1. 使用 Python 内置的 queue.Queue(适用于单机应用)

queue.Queue 提供了线程安全的队列操作,适合在多线程应用中使用。

import queue
import threading
import time # 创建一个先进先出(FIFO)队列
msg_queue = queue.Queue() # 生产者线程
def producer():
for i in range(5):
time.sleep(1) # 模拟一些处理
msg = f"消息{i}"
msg_queue.put(msg) # 将消息放入队列
print(f"生产者放入:{msg}") # 消费者线程
def consumer():
while True:
msg = msg_queue.get() # 从队列获取消息
if msg is None: # 终止条件
break
print(f"消费者处理:{msg}")
msg_queue.task_done() # 标记任务已完成 # 创建生产者和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer) # 启动线程
producer_thread.start()
consumer_thread.start() # 等待生产者线程完成
producer_thread.join() # 向消费者线程发送终止信号
msg_queue.put(None) # 等待消费者线程完成
consumer_thread.join()

2. 使用 Redis(适用于分布式应用)

Redis 是一个高效的内存数据存储,可以用作分布式消息队列。你可以使用 redis-py 库与 Redis 进行交互。

pip install redis
import redis
import time # 创建 Redis 连接
r = redis.StrictRedis(host='localhost', port=6379, db=0) # 生产者:将消息放入队列
def producer():
for i in range(5):
time.sleep(1) # 模拟一些处理
msg = f"消息{i}"
r.lpush('msg_queue', msg) # 将消息推送到队列
print(f"生产者放入:{msg}") # 消费者:从队列中获取消息
def consumer():
while True:
msg = r.brpop('msg_queue')[1].decode('utf-8') # 从队列中获取消息
print(f"消费者处理:{msg}") # 启动生产者和消费者
producer()
consumer()

3. 使用 RabbitMQ(适用于更复杂的消息传递)

RabbitMQ 是一个强大的消息代理系统,支持多种消息队列模式。如果需要高度可靠和高性能的消息队列,可以使用 pika 库连接 RabbitMQ。

pip install pika
import pika

# 连接到 RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel() # 声明一个队列
channel.queue_declare(queue='msg_queue') # 生产者:发送消息
def producer():
for i in range(5):
msg = f"消息{i}"
channel.basic_publish(exchange='',
routing_key='msg_queue',
body=msg)
print(f"生产者发送:{msg}") # 消费者:接收并处理消息
def consumer(ch, method, properties, body):
print(f"消费者处理:{body.decode('utf-8')}") # 启动消费者
channel.basic_consume(queue='msg_queue', on_message_callback=consumer, auto_ack=True) # 启动生产者和消费者
producer()
print('等待消息...')
channel.start_consuming()

选择合适的实现

  • 如果你是单机应用并且需要线程安全的队列,使用 queue.Queue
  • 如果你的应用是分布式的,使用 RedisRabbitMQ 更加合适,它们提供了高可用性、消息持久化和可靠的消息传递机制。

如何把 http 请求放在队列中执行

将 HTTP 请求放入队列并异步执行的场景通常用于处理高并发、后台任务、延迟任务等情况。你可以使用消息队列系统(如 queue.QueueRedisRabbitMQ)来将 HTTP 请求放入队列,消费队列中的任务并执行相应的 HTTP 请求。

这里我会展示几种不同的实现方式,供你参考。

1. 使用 queue.Queuerequests

你可以将 HTTP 请求封装为任务,并将其放入队列中,然后使用多个消费者线程异步处理队列中的请求。

import queue
import threading
import time
import requests # 创建一个队列
task_queue = queue.Queue() # HTTP 请求任务处理函数
def handle_request():
while True:
url = task_queue.get() # 从队列中获取任务
if url is None: # 终止条件
break
try:
response = requests.get(url)
print(f"请求 {url} 的响应状态: {response.status_code}")
except Exception as e:
print(f"请求 {url} 失败: {e}")
task_queue.task_done() # 标记任务完成 # 生产者:将 HTTP 请求放入队列
def producer():
urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3"
] for url in urls:
print(f"将 URL {url} 放入队列")
task_queue.put(url)
time.sleep(1) # 模拟任务产生的延迟 # 创建多个消费者线程
consumer_threads = []
for i in range(3):
t = threading.Thread(target=handle_request)
t.start()
consumer_threads.append(t) # 启动生产者线程
producer_thread = threading.Thread(target=producer)
producer_thread.start() # 等待生产者线程完成
producer_thread.join() # 向消费者线程发送终止信号
for _ in range(3):
task_queue.put(None) # 等待消费者线程完成
for t in consumer_threads:
t.join()

2. 使用 Redisrequests

Redis 可以作为一个分布式的消息队列,适用于分布式系统中将 HTTP 请求放入队列并异步执行。你可以使用 Redis 的列表数据结构(lpushbrpop)来实现。

import redis
import requests
import time # 创建 Redis 连接
r = redis.StrictRedis(host='localhost', port=6379, db=0) # 生产者:将 HTTP 请求放入队列
def producer():
urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3"
] for url in urls:
print(f"将 URL {url} 放入 Redis 队列")
r.lpush('task_queue', url)
time.sleep(1) # 模拟任务产生的延迟 # 消费者:从队列中获取请求并执行
def consumer():
while True:
url = r.brpop('task_queue')[1].decode('utf-8') # 从队列中获取任务
try:
response = requests.get(url)
print(f"请求 {url} 的响应状态: {response.status_code}")
except Exception as e:
print(f"请求 {url} 失败: {e}") # 启动生产者和消费者
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer) producer_thread.start()
consumer_thread.start() # 等待生产者线程完成
producer_thread.join() # 由于 Redis 队列会一直阻塞等待任务,可以根据需要添加退出逻辑

3. 使用 RabbitMQrequests

RabbitMQ 提供了强大的消息队列机制,适合用于大规模的消息传递。你可以创建一个任务队列,将 HTTP 请求放入队列中,并通过消费者处理队列中的请求。

import pika
import requests
import time # 连接到 RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel() # 声明队列
channel.queue_declare(queue='http_requests') # 生产者:将 HTTP 请求放入队列
def producer():
urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3"
] for url in urls:
print(f"将 URL {url} 放入 RabbitMQ 队列")
channel.basic_publish(exchange='',
routing_key='http_requests',
body=url)
time.sleep(1) # 模拟任务产生的延迟 # 消费者:处理 HTTP 请求
def consumer(ch, method, properties, body):
url = body.decode('utf-8')
try:
response = requests.get(url)
print(f"请求 {url} 的响应状态: {response.status_code}")
except Exception as e:
print(f"请求 {url} 失败: {e}") # 启动消费者
channel.basic_consume(queue='http_requests', on_message_callback=consumer, auto_ack=True) # 启动生产者
producer_thread = threading.Thread(target=producer)
producer_thread.start() # 启动消费者并等待消息
print('等待消费者处理 HTTP 请求...')
producer_thread.join()
channel.start_consuming()

4. 使用 Celery 异步任务队列

Celery 是一个强大的异步任务队列,适用于分布式任务执行。通过 Celery,你可以把 HTTP 请求封装为任务,放入队列中进行异步执行。

首先,你需要安装 Celeryrequests

pip install celery requests

然后在 celery.py 中配置 Celery:

from celery import Celery
import requests app = Celery('http_requests', broker='redis://localhost:6379/0') @app.task
def fetch_url(url):
try:
response = requests.get(url)
print(f"请求 {url} 的响应状态: {response.status_code}")
except Exception as e:
print(f"请求 {url} 失败: {e}")

然后在主程序中提交任务:

from celery import Celery
from celery.py import fetch_url # 添加任务到队列
fetch_url.apply_async(args=["https://jsonplaceholder.typicode.com/posts/1"])
fetch_url.apply_async(args=["https://jsonplaceholder.typicode.com/posts/2"])
fetch_url.apply_async(args=["https://jsonplaceholder.typicode.com/posts/3"])

启动 Celery Worker:

celery -A celery worker --loglevel=info

总结

  • queue.Queue:适用于单机和多线程环境,可以通过队列异步执行 HTTP 请求。
  • Redis:适用于分布式环境,将 HTTP 请求放入 Redis 队列,多个消费者异步执行。
  • RabbitMQ:适合高并发任务和消息传递的分布式环境,使用队列来管理 HTTP 请求。
  • Celery:适用于大规模异步任务队列的场景,可以使用 Redis 或其他消息中间件作为代理。

简介下这个 .net 开发的小系统

https://kf.shengxunwei.com/

升讯威在线客服与营销系统是一款客服软件,但更重要的是一款营销利器。

  • 可以追踪正在访问网站或使用 APP 的所有访客,收集他们的浏览情况,使客服能够主动出击,施展话术,促进成单。
  • 可嵌入网站、手机 APP、公众号、或者通过 URL 地址直接联系客服。
  • 支持访客信息互通,可传输访客标识、名称和其它任意信息到客服系统,与您的业务系统对接。
  • 可全天候 7 × 24 小时挂机运行,网络中断,拔掉网线,手机飞行模式,不掉线不丢消息,欢迎实测。

希望能够打造: 开放、开源、共享。努力打造 .net 社区的一款优秀开源产品。

钟意的话请给个赞支持一下吧,谢谢~

如何通过 Python 实现一个消息队列,为在线客服系统与海外运营的APP对接的更多相关文章

  1. .net core 和 WPF 开发升讯威在线客服系统:怎样实现拔网线也不丢消息的高可靠通信(附视频)

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...

  2. 百度AI开放平台 UNIT平台开发在线客服 借助百度的人工智能如何开发一个在线客服系统

    这段时间在研究一些人工智能的产品,对比了国内几家做人工智能在线客服的,有些接口是要收费的,有些是免费的,但是做了很多限制,比如每天调用的接口次数限制是100次.后来就找到了百度的AI,大家也知道,目前 ...

  3. (原创)用.NET Core实现一个在线客服系统(上篇)

    前言 没有视频的介绍显得尤为空白仓促.所以,如果你不赶时间,看看视频先 → → 戳我看视频 ← ←  在线演示访客端:http://role.fuyue.xyz/visitor/index客服端:ht ...

  4. Python操作rabbitmq消息队列持久化

    消息队列持久化 Python操作rabbit消息队列的持久化,如下: # 创建一个名为balance的队列,对queue进行durable持久化设为True(持久化第一步)channel.queue_ ...

  5. openresty 学习笔记番外篇:python访问RabbitMQ消息队列

    openresty 学习笔记番外篇:python访问RabbitMQ消息队列 python使用pika扩展库操作RabbitMQ的流程梳理. 客户端连接到消息队列服务器,打开一个channel. 客户 ...

  6. Python 番外 消息队列设计精要

    消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的Active ...

  7. skynet源代码学习 - 从全局队列中弹出/压入一个消息队列过程

    学习云风的skynet源代码,简单记录下. void skynet_globalmq_push(struct message_queue * queue) { struct global_queue ...

  8. 什么鬼,面试官竟然让我用Redis实现一个消息队列!!?

    GitHub 9.4k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 9.4k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 9.4k Star 的 ...

  9. 用过消息队列?Kafka?能否手写一个消息队列?懵

    是否有同样的经历?面试官问你做过啥项目,我一顿胡侃,项目利用到了消息队列,kafka,rocketMQ等等. 好的,那请开始你的表演,面试官递过一支笔:给我手写一个消息队列!!WHAT? 为了大家遇到 ...

  10. 进阶高阶IoT架构-教你如何简单实现一个消息队列

    前言 消息队列是软件系统领域用来实现系统间通信最广泛的中间件.基于消息队列的方式是指由应用中的某个系统负责发送消息,由关心这条消息的相关系统负责接收消息,并在收到消息后进行各自系统内的业务处理.消息可 ...

随机推荐

  1. 使用 httputils + protostuff 实现高性能 rpc

    1.先讲讲 protostuf protostuf 一直是高性能序列化的代表之一.但是用起来,可难受了,你得先申明 protostuf 配置文件,并且要把这个配置文件转成类.所以必然要学习新语法.新工 ...

  2. 张高兴的 Raspberry Pi AI 开发指南:(三)将自定义模型编译为 Hailo NPU 的 .hef 模型

    目录 Python 环境配置 转换 量化 编译 参考 在上一篇博客中,探讨了如何使用 Python 和 hailo_model_zoo 中预编译的模型来实现目标检测.本篇博客将深入介绍如何将用户自定义 ...

  3. Pytest接口自动化测试框架Python自动化测试开发

    一.引言 在软件开发过程中,接口测试是确保软件各个组件之间数据传输和功能交互正常工作的重要环节.通过接口测试,可以提高软件的整体质量和稳定性.Pytest是一个流行的Python自动化测试框架,提供了 ...

  4. SQLServer无法远程连接的解决方法

    ​服务器端: 打开SQLServer配置管理器 - SQLServer 网络配置- MSSQLSERVER的协议-TCP/IP 启用 运行输入Services.msc,重启MSSQLSERVER服务. ...

  5. 【金TECH频道】企业架构转型组合拳来袭,助力金融机构一臂之力

    当前,数字化转型已经成为时代共性课题在政策和技术的双重指引下金融机构逐渐走向差异化竞争的格局面对转型阵痛以契合.明晰的战略规划及企业架构调整来辅助业务变革成为助力企业数字化转型的有效路径金融机构也纷纷 ...

  6. bytecode 生成器

    基础 objectweb asm 很难用,找了几个高级点的. activej codegen 这个库很像 .net DLR 风格,采用 Expression 抽象,例如 Expressions.add ...

  7. 【NAS】绿联NAS+alist+lsky+natfrp 实现图床服务

    alist 安装与配置 值得一提的就是,映射的data是配置相关的,让绿联直接默认路径就行,不需要手动设置 但是文件保存位置的映射的话,为了方便,可以单独映射到一个方便访问的文件夹,(但是要注意下权限 ...

  8. virtualbox设置了共享文件夹却无权限访问

    在virtualbox中设置共享文件夹后,然后登陆ubuntu系统访问共享文件夹,发现没有权限.查看共享文件夹的属性可知,共享文件夹的所有者是root,所属的组是vboxsf.以用户登录的时候,自然是 ...

  9. 快速解决MySQL:Table xxx is marked as crashed and should be repaired五个办法

    查看MySQL错误日志看到 Table xxx  is marked as crashed and should be repaired 解决办法如下 第一种: 1.首先进入mysql命令台: mys ...

  10. Qt开发经验小技巧181-185

    Qt天生就是linux的,从linux开始发展起来的,所以不少Qt程序员经常的开发环境是linux,比如常用的ubuntu等系统,整理了一点常用的linux命令. 命令 功能 sudo -s 切换到管 ...