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

如何在Slackbot中发送进度消息?长任务超时更新问题求助

Slackbot长任务超时更新消息的问题修复

问题根源

  • 同步事件处理函数与异步任务不兼容:你用def定义的event_message是同步函数,但里面启动的run_task是异步协程。在同步上下文里直接调用asyncio.ensure_future,协程无法被正确调度执行,自然不会触发超时更新。
  • 阻塞任务卡死事件循环:如果long_running_task实际是阻塞性的同步代码(哪怕写成async def),await它会直接占满整个事件循环,asyncio.wait_for的超时检查根本没机会运行,超时逻辑完全失效。

解决方案

方案1:改用AsyncApp(推荐)

直接切换到异步版本的App,整个流程都在异步上下文里,调度逻辑更顺畅:

import asyncio
from slack_bolt.async_app import AsyncApp

app = AsyncApp()

# 模拟阻塞长任务(同步函数)
def long_running_task():
    import time
    time.sleep(20)  # 模拟长耗时操作
    return "任务完成"

@app.event("message")
async def event_message(client, event, say, logger):
    # 发送初始加载提示
    initial_msg = await say("Loading..")
    msg_ts = initial_msg["ts"]
    channel = event["channel"]

    async def track_and_update():
        try:
            # 把阻塞任务丢到线程池执行,避免卡死事件循环
            loop = asyncio.get_event_loop()
            await asyncio.wait_for(loop.run_in_executor(None, long_running_task), timeout=15)
        except asyncio.TimeoutError:
            # 超时后更新消息
            await client.chat_update(
                channel=channel,
                ts=msg_ts,
                text="Still loading..."
            )
        else:
            # 任务顺利完成,再更新一次消息(可选)
            await client.chat_update(
                channel=channel,
                ts=msg_ts,
                text="任务已完成!"
            )

    # 启动异步任务,不用等待它结束,直接返回
    asyncio.create_task(track_and_update())

if __name__ == "__main__":
    app.start(port=3000)

方案2:同步App中用线程隔离任务

如果不想换AsyncApp,就用线程把长任务和超时检查隔离开:

import time
import threading
from slack_bolt import App

app = App()

def long_running_task():
    import time
    time.sleep(20)
    return "任务完成"

def run_long_task(client, channel, msg_ts, stop_event):
    try:
        result = long_running_task()
        # 任务完成后更新消息
        client.chat_update(channel=channel, ts=msg_ts, text="任务已完成!")
    except Exception as e:
        client.chat_update(channel=channel, ts=msg_ts, text="任务执行失败")
    finally:
        # 通知超时检查线程停止
        stop_event.set()

def check_timeout(client, channel, msg_ts, stop_event):
    # 等15秒,任务还没结束就更新消息
    time.sleep(15)
    if not stop_event.is_set():
        client.chat_update(channel=channel, ts=msg_ts, text="Still loading...")

@app.event("message")
def event_message(client, event, say, logger):
    initial_msg = say("Loading..")
    msg_ts = initial_msg["ts"]
    channel = event["channel"]

    # 创建事件用于通知超时线程任务状态
    stop_event = threading.Event()

    # 启动超时检查线程
    timeout_thread = threading.Thread(target=check_timeout, args=(client, channel, msg_ts, stop_event))
    timeout_thread.start()

    # 启动长任务线程
    task_thread = threading.Thread(target=run_long_task, args=(client, channel, msg_ts, stop_event))
    task_thread.start()

关键注意事项

  • 只要长任务是阻塞代码,就绝对不能直接在异步协程里await它——必须用run_in_executor(异步场景)或者线程(同步场景)隔离,不然整个Slackbot会被卡死。
  • 同步App里的Slack客户端方法是同步的,可以直接在线程里调用;异步App里必须用await调用异步方法。
  • 超时逻辑的核心是:让超时检查和长任务互不干扰,别让长任务把处理超时的线程/事件循环堵死。

内容的提问来源于stack exchange,提问作者Ahmad Abdallah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 03:43:13