fix: 设备删除增加用户校验、ACK 在线状态刷新改非阻塞、停止跟踪日志
- AppDeviceServiceImpl#deleteWithValidByIds 校验设备归属当前用户, 避免任意已登录用户越权删除其他用户的设备及关联数据 - MqttCommandAckService#refreshDeviceOnline 由 lock.lock 改为 tryLock, 防止 MQTT 处理线程在状态刷新锁上排队堆积;状态写入幂等,跳过本次刷新 由后续 ACK 兜底 - 从版本控制中移除 logs/ 历史日志,gitignore 已忽略该目录 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,10 +75,14 @@ public class MqttCommandAckService implements IDeviceCommandAckHandler {
|
||||
return;
|
||||
}
|
||||
ack.setDeviceNo(deviceNo);
|
||||
withCommandLock(ack.getCommandId(), () -> {
|
||||
boolean ackSaved = withCommandLock(ack.getCommandId(), () -> {
|
||||
deletePending(ack.getCommandId());
|
||||
RedisUtils.setCacheObject(ackKey(ack.getCommandId()), ack, Duration.ofSeconds(mqttProperties.getCommandAck().getAckTtlSeconds()));
|
||||
});
|
||||
if (!ackSaved) {
|
||||
log.warn("[MQTT] ACK 处理未获得命令锁,本次跳过 设备编号={} 命令编号={}", deviceNo, ack.getCommandId());
|
||||
return;
|
||||
}
|
||||
refreshDeviceOnline(deviceNo);
|
||||
log.info("[MQTT] 收到命令确认 设备编号={} 命令编号={} 状态={}", deviceNo, ack.getCommandId(), ack.getStatus());
|
||||
}
|
||||
@@ -99,10 +103,14 @@ public class MqttCommandAckService implements IDeviceCommandAckHandler {
|
||||
ack.setStatus("1");
|
||||
ack.setMessage(payload);
|
||||
|
||||
withCommandLock(commandId, () -> {
|
||||
boolean ackSaved = withCommandLock(commandId, () -> {
|
||||
deletePending(commandId);
|
||||
RedisUtils.setCacheObject(ackKey(commandId), ack, Duration.ofSeconds(mqttProperties.getCommandAck().getAckTtlSeconds()));
|
||||
});
|
||||
if (!ackSaved) {
|
||||
log.warn("[MQTT] 非 JSON ACK 处理未获得命令锁,本次跳过 设备编号={} 命令编号={}", deviceNo, commandId);
|
||||
return;
|
||||
}
|
||||
log.info("[MQTT] 收到非 JSON 命令确认 设备编号={} 命令编号={} 消息体={}", deviceNo, commandId, payload);
|
||||
}
|
||||
|
||||
@@ -177,8 +185,11 @@ public class MqttCommandAckService implements IDeviceCommandAckHandler {
|
||||
RLock lock = RedisUtils.getClient().getLock(DEVICE_STATUS_LOCK_PREFIX + deviceNo);
|
||||
boolean locked = false;
|
||||
try {
|
||||
lock.lock(10, TimeUnit.SECONDS);
|
||||
locked = true;
|
||||
locked = lock.tryLock(0, 10, TimeUnit.SECONDS);
|
||||
if (!locked) {
|
||||
// 其他线程正在刷新,本次跳过;状态写入幂等,下条 ACK 仍会兜底刷新
|
||||
return;
|
||||
}
|
||||
Map<String, Object> statusCache = new HashMap<>();
|
||||
statusCache.put("deviceNo", deviceNo);
|
||||
statusCache.put("status", "1");
|
||||
@@ -193,6 +204,9 @@ public class MqttCommandAckService implements IDeviceCommandAckHandler {
|
||||
.set(AppDevice::getStatus, "1")
|
||||
.eq(AppDevice::getDeviceNo, deviceNo)
|
||||
);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.warn("[MQTT] 刷新设备在线状态被中断 设备编号={}", deviceNo);
|
||||
} finally {
|
||||
if (locked && lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
@@ -209,20 +223,23 @@ public class MqttCommandAckService implements IDeviceCommandAckHandler {
|
||||
pendingIds().remove(commandId);
|
||||
}
|
||||
|
||||
private void withCommandLock(String commandId, Runnable action) {
|
||||
private boolean withCommandLock(String commandId, Runnable action) {
|
||||
RLock lock = RedisUtils.getClient().getLock(mqttProperties.getCommandAck().getRetryLockKeyPrefix() + commandId);
|
||||
boolean locked = false;
|
||||
try {
|
||||
locked = lock.tryLock(0, mqttProperties.getCommandAck().getRetryLockTtlMs(), TimeUnit.MILLISECONDS);
|
||||
if (!locked) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
action.run();
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.warn("[MQTT] 命令锁等待被中断 命令编号={}", commandId);
|
||||
return false;
|
||||
} catch (RuntimeException e) {
|
||||
log.error("[MQTT] 命令锁内处理失败 命令编号={}", commandId, e);
|
||||
return false;
|
||||
} finally {
|
||||
if (locked && lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
|
||||
Reference in New Issue
Block a user