YunaiV/ruoyi-vue-pro · critical · RuntimeException
HTTP Hook 服务启动失败
Error message
HTTP Hook 服务启动失败
What it means
Thrown when the Vert.x HTTP server hosting the EMQX HTTP Hook endpoints (/mqtt/auth, /mqtt/acl, /mqtt/event) fails to start. The code calls httpServer.listen() with a 10-second join (.get(10, TimeUnit.SECONDS)); any bind failure, SSL cert/key load error, or listen timeout is wrapped and rethrown as RuntimeException. Because IotEmqxProtocol.start() calls this first and propagates, it aborts the whole protocol instance startup.
Source
Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxProtocol.java:229
if (httpConfig != null && Boolean.TRUE.equals(httpConfig.getSslEnabled())) {
Assert.notBlank(httpConfig.getSslCertPath(), "EMQX HTTP SSL 证书路径(emqx.http.ssl-cert-path)不能为空");
Assert.notBlank(httpConfig.getSslKeyPath(), "EMQX HTTP SSL 私钥路径(emqx.http.ssl-key-path)不能为空");
PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions()
.setKeyPath(httpConfig.getSslKeyPath())
.setCertPath(httpConfig.getSslCertPath());
options.setSsl(true).setKeyCertOptions(pemKeyCertOptions);
}
try {
httpServer = vertx.createHttpServer(options)
.requestHandler(router)
.listen()
.toCompletionStage().toCompletableFuture()
.get(10, TimeUnit.SECONDS);
log.info("[startHttpServer][IoT EMQX 协议 {} HTTP Hook 服务启动成功, port: {}, ssl: {}]",
getId(), properties.getPort(), httpConfig != null && Boolean.TRUE.equals(httpConfig.getSslEnabled()));
} catch (Exception e) {
log.error("[startHttpServer][IoT EMQX 协议 {} HTTP Hook 服务启动失败, port: {}]", getId(), properties.getPort(), e);
throw new RuntimeException("HTTP Hook 服务启动失败", e);
}
}
private void stopHttpServer() {
if (httpServer == null) {
return;
}
try {
httpServer.close().toCompletionStage().toCompletableFuture()
.get(5, TimeUnit.SECONDS);
log.info("[stopHttpServer][IoT EMQX 协议 {} HTTP Hook 服务已停止]", getId());
} catch (Exception e) {
log.error("[stopHttpServer][IoT EMQX 协议 {} HTTP Hook 服务停止失败]", getId(), e);
} finally {
httpServer = null;
}
}
View on GitHub (pinned to 0418084e22)
Solutions
- Check the port is free: ss -ltnp | grep <port> or lsof -i:<port>, then free it or change properties.port.
- If SSL is enabled, verify emqx.http.ssl-cert-path and emqx.http.ssl-key-path exist and are readable by the gateway process, and form a valid key/cert pair (openssl x509 -noout -modulus matches key).
- Ensure only one gateway instance binds the port (no duplicate protocol instances with the same port).
- Raise the 10s listen timeout or check Vert.x event-loop health if bind is slow under load.
Defensive patterns
Strategy: validation
Validate before calling
// before start(), confirm the hook port is free and SSL files (if enabled) exist
try (ServerSocket probe = new ServerSocket(properties.getPort())) {
// port is free
} catch (IOException e) {
throw new IllegalStateException("HTTP Hook 端口被占用: " + properties.getPort(), e);
}
if (Boolean.TRUE.equals(httpConfig.getSslEnabled())) {
java.nio.file.Files.readString(java.nio.file.Path.of(httpConfig.getSslCertPath()));
java.nio.file.Files.readString(java.nio.file.Path.of(httpConfig.getSslKeyPath()));
} Try / catch
// in IotProtocolManager.start(), isolate each protocol so one bind failure doesn't abort all
for (ProtocolProperties config : protocolConfigs) {
try {
IotProtocol protocol = createProtocol(config);
if (protocol != null) { protocol.start(); protocols.add(protocol); }
} catch (Exception e) {
log.error("[start][协议实例 {} 启动失败,跳过]", config.getId(), e);
}
} Prevention
- Reserve the hook port exclusively for the gateway (document it, allocate from a range).
- Validate SSL cert/key files in the constructor (Assert + Files.exists) so misconfiguration fails fast.
- Run only one gateway instance per host:port; use a process supervisor that prevents duplicates.
- Isolate per-protocol startup failures in the manager loop so a single bad port doesn't block other protocols.
When it happens
Trigger: properties.getPort() is already bound by another process; SSL enabled (emqx.http.ssl-enabled=true) but ssl-cert-path / ssl-key-path is missing, unreadable, or invalid PEM; the OS denies the bind (privileged port <1024 without permission); listen() does not complete within 10 seconds.
Common situations: Port conflict with another EMQX protocol instance or service; running two gateway processes; SSL cert path typo or wrong working directory; cert/key file permissions; EMQX configured to call back on a port the gateway never opened.
Related errors
- MQTT Client 启动失败: 连接 Broker 失败
- [startTcpServer][TCP Server 启动失败]
- AreaUtils 初始化失败
- IPUtils 初始化失败
- Modbus 读取失败 [slaveId=%d, identifier=%s, functionCode=%d, add
AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14).
Data as JSON: /api/errors/b3c199a11557a2d9.
Report an issue: GitHub.