如何在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
相关产品推荐
相关产品推荐

