Heroku部署Java Discord机器人报Error R10启动超时如何解决
问题根因
Heroku对web类型dyno有强制启动校验规则:进程必须在启动后90秒内监听平台动态分配的$PORT端口,否则直接触发R10启动超时错误,发送SIGKILL信号强制终止进程。
你的JDA Discord机器人本质是主动向外发起WebSocket连接的客户端程序,本身没有内置HTTP服务,不会监听任何端口。哪怕你在启动参数、application.properties里配置了server.port也不会生效:
- 纯JDA项目没有引入Spring Web等Web依赖,根本不会读取这个配置绑定端口
- 原Procfile里把
-Dserver.port写在了-jar参数后面,这个参数会被当成传给主类的命令行参数,不会被JVM识别为系统属性,就算有Web依赖也读不到这个配置
从日志里能看到JDA已经正常登录加载完成,说明程序本身运行逻辑没问题,就是过不了web dyno的端口绑定校验才被杀。
修复方案
二选一即可,优先选方案1,改动最小最适配机器人场景。
方案1:切换dyno类型为worker(推荐)
worker类型dyno是Heroku专门给后台常驻任务设计的,没有强制端口绑定校验,完全适配Discord机器人这类长驻客户端程序,操作步骤:
- 修改项目根目录的
Procfile,把进程类型从web改成worker,删掉没用的端口配置参数,最终内容:
worker: java $JAVA_OPTS -jar target/DiscordBot-1.0-SNAPSHOT-jar-with-dependencies.jar
- 代码推送到Heroku完成部署后,执行命令调整dyno分配,关闭web进程、启动worker进程:
heroku ps:scale web=0 worker=1
重新部署后程序就不会被R10规则误杀,JDA连接成功后可以长期稳定运行。
方案2:添加轻量HTTP端口监听(仅适用于必须使用web dyno的场景)
如果你有特殊需求必须使用web类型dyno,只需要在程序启动逻辑里加一个极简HTTP服务,绑定$PORT端口通过Heroku校验即可,不需要引入重型Web框架,直接用JDK内置的HttpServer就能实现:
- 把原有主类启动逻辑调整为如下形式,保留原有JDA业务代码,新增端口监听部分:
import com.sun.net.httpserver.HttpServer; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import java.net.InetSocketAddress; public class BotMain { public static void main(String[] args) throws Exception { // 原有JDA初始化逻辑保持不变 JDA jda = JDABuilder.createDefault("你的机器人Token") .build() .awaitReady(); // 新增端口监听逻辑,通过Heroku启动校验 String portEnv = System.getenv("PORT"); if (portEnv != null) { int port = Integer.parseInt(portEnv); HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); // 随便返回个200响应即可,仅用于占用端口通过校验 server.createContext("/", exchange -> { String resp = "Bot running"; exchange.sendResponseHeaders(200, resp.getBytes().length); exchange.getResponseBody().write(resp.getBytes()); exchange.close(); }); server.setExecutor(null); server.start(); } } }
- 改完重新打包部署,程序启动后会正常绑定分配的端口,不会再触发R10超时。
内容的提问来源于stack exchange,提问作者Andrei Raevski
相关产品推荐
相关产品推荐

