You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 04:15:37