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

如何解决Heroku启动时出现的R12(Exit timeout)错误?

问题根因

你触发Heroku R12错误的核心原因有两个:

  • 用了同步阻塞的time.sleep(),会直接卡住整个异步事件循环,且你直接await cool_down_ended(message)会导致on_message事件被阻塞24分钟才能返回
  • 进程收到Heroku发送的SIGTERM重启信号时,没有对应处理逻辑退出挂起的延时任务,超过30秒无法正常退出就会被强制杀进程,返回状态码137
简便修复方案

第一步:替换阻塞sleep,把延时任务改为后台运行

不要直接await延时函数,用asyncio.create_task将其放到后台执行,同时把time.sleep换成异步非阻塞的asyncio.sleep,避免卡住事件循环:

import asyncio

# 用来存储所有挂起的延时任务,后续处理进程退出时会用到
pending_tasks = set()

@client.listen()
async def on_message(message):
    """
    检测用户发送的'bhwagon'指令,24分钟后给用户发提醒DM
    :param message: 用户发送的消息
    :return: 给用户发送的冷却结束提醒私信
    """
    channel = client.get_channel(int(WAGON_CHANNEL))

    if message.content.startswith("bhwagon"):
        channel = message.channel
        # 将延时任务放到后台执行,不阻塞当前事件响应
        task = asyncio.create_task(cool_down_ended(message))
        pending_tasks.add(task)
        # 任务执行完成后自动从待处理集合中移除
        task.add_done_callback(pending_tasks.discard)


async def cool_down_ended(message):
    """
    用户发送'bhwagon'指令24分钟后,给发送者发私信提醒冷却结束
    :param message: 用户发送的原始消息
    :return: 给用户发送的提醒私信
    """
    # 替换为异步非阻塞sleep,不会卡住整个事件循环
    await asyncio.sleep(1440)  # 24分钟 = 1440秒
    await message.author.send("你的偷车冷却已经结束了🎩 可以再去刷一波材料了!")

第二步:添加SIGTERM信号处理逻辑,收到终止信号时主动清退任务

注册信号处理逻辑,当Heroku发送SIGTERM要求重启进程时,主动取消所有挂起的延时任务,让进程在30秒内正常退出:

import signal

def handle_sigterm(*args):
    # 取消所有还在等待的延时任务
    for task in pending_tasks:
        task.cancel()
    # 正常关闭机器人客户端
    asyncio.create_task(client.close())

# 注册SIGTERM信号的处理函数
signal.signal(signal.SIGTERM, handle_sigterm)

修改完成后重新部署即可解决R12报错问题。

内容的提问来源于stack exchange,提问作者yet-it-compiles

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:45:03