如何实现Discord Bot任务完成后向指定用户发送消息及附件
解决Discord Bot异步任务通知与离线消息问题
一、异步执行任务并在完成后通知用户
你当前使用subprocess.call会阻塞Bot的事件循环,导致进程挂起报错。推荐两种实用方案:
方案1:用asyncio异步等待子进程完成(最简单直接)
直接在on_message中使用asyncio.create_subprocess_shell异步启动任务,等待其完成后再发送结果。这种方式不会阻塞Bot的事件循环,从根源避免报错:
import asyncio import discord @client.event async def on_message(message): if message.author == client.user or not message.content: return msg_content = message.content author_id = message.author.id # 保存用户ID,用于后续精准发消息 # 异步启动子进程,捕获输出和错误信息 process = await asyncio.create_subprocess_shell( f"python JOB.py \"{msg_content}\" {author_id}", # 转义空格避免参数拆分错误 stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) # 等待任务执行完成,获取输出结果 stdout, stderr = await process.communicate() output = stdout.decode().strip() if process.returncode == 0: # 假设JOB.py执行成功后输出生成的文件路径 try: await message.author.send("任务已完成!", file=discord.File(output)) except Exception as e: print(f"发送消息失败:{str(e)}") else: # 任务出错时返回错误详情 await message.author.send(f"任务执行失败:\n{stderr.decode().strip()}")
方案2:用消息队列实现跨进程通知(适合高并发/超长时间任务)
如果任务数量多、耗时极长,不想让on_message等待,可以用Redis消息队列让JOB.py主动通知Bot:
Bot端代码:
import json import redis import asyncio from discord.ext import tasks, commands client = commands.Bot(command_prefix="!", intents=discord.Intents.all()) r = redis.Redis(host="localhost", port=6379, db=0) pubsub = r.pubsub() pubsub.subscribe("job_completed") @tasks.loop(seconds=1) async def check_job_queue(): # 监听队列中的任务完成通知 msg = pubsub.get_message() if msg and msg["type"] == "message": data = json.loads(msg["data"].decode()) user_id = data["user_id"] file_path = data["file_path"] # 获取用户对象并发送结果 user = client.get_user(user_id) if user: try: await user.send("任务完成!", file=discord.File(file_path)) except Exception as e: print(f"发送失败:{str(e)}") @client.event async def on_ready(): check_job_queue.start() print("Bot已上线") @client.event async def on_message(message): if message.author == client.user or not message.content: return # 异步启动子进程,无需等待完成 await asyncio.create_subprocess_shell( f"python JOB.py \"{message.content}\" {message.author.id}" )
JOB.py代码(任务完成后推送通知到队列):
import json import redis # 执行你的耗时任务逻辑... # 任务完成后生成文件路径,例如generated_file = "output.pdf" # 连接Redis并发送任务完成通知 r = redis.Redis(host="localhost", port=6379, db=0) result_data = { "user_id": 123456789, # 替换为传入的实际用户ID "file_path": "output.pdf" } r.publish("job_completed", json.dumps(result_data))
二、离线用户的消息与附件送达问题
- 正常情况:如果用户未屏蔽Bot,且允许接收私信(包括非好友私信,或Bot与用户在同一服务器),私信和附件会被Discord服务器暂存,用户下次上线时会自动收到。
- 限制情况:如果用户设置了「仅接受好友的私信」且未添加Bot为好友,Bot将无法发送私信。此时需提示用户添加Bot为好友,或确保Bot与用户在同一服务器内(服务器内的私信不受好友关系限制)。
内容的提问来源于stack exchange,提问作者alex alex
相关产品推荐
相关产品推荐

