20260319:1调整线程traceId;2获取ICCID/IMEI(暂存版)
This commit is contained in:
parent
90b078323b
commit
681cd4a9db
@ -107,7 +107,7 @@
|
|||||||
<maxHistory>3</maxHistory>
|
<maxHistory>3</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{HH:mm:ss.SSS} [%method,%line] - %msg%n</pattern>
|
<pattern>%d{HH:mm:ss.SSS} [%thread] [%X{traceId}] [%method,%line] - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
<level>INFO</level>
|
<level>INFO</level>
|
||||||
@ -123,7 +123,7 @@
|
|||||||
<maxHistory>3</maxHistory>
|
<maxHistory>3</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{HH:mm:ss.SSS} [%method,%line] - %msg%n</pattern>
|
<pattern>%d{HH:mm:ss.SSS} [%thread] [%X{traceId}] [%method,%line] - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
<level>INFO</level>
|
<level>INFO</level>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.fastbee.common.config;
|
package com.fastbee.common.config;
|
||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -105,6 +106,7 @@ public class DeviceTask {
|
|||||||
executor.setMaxPoolSize(maxSize);
|
executor.setMaxPoolSize(maxSize);
|
||||||
executor.setKeepAliveSeconds(keepAlive);
|
executor.setKeepAliveSeconds(keepAlive);
|
||||||
executor.setQueueCapacity(queueCapacity);
|
executor.setQueueCapacity(queueCapacity);
|
||||||
|
executor.setTaskDecorator(TraceIdUtils::wrapWithMdc);
|
||||||
// 线程池对拒绝任务的处理策略
|
// 线程池对拒绝任务的处理策略
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
|
||||||
//线程池名的前缀
|
//线程池名的前缀
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package com.fastbee.common.utils;
|
|||||||
import com.fastbee.common.utils.uuid.IdUtils;
|
import com.fastbee.common.utils.uuid.IdUtils;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,6 +103,81 @@ public class TraceIdUtils {
|
|||||||
return MDC.get(TRACE_ID_KEY);
|
return MDC.get(TRACE_ID_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保当前线程 MDC 中存在 TraceId。
|
||||||
|
* - 已存在:直接返回
|
||||||
|
* - 不存在:生成并写入 MDC
|
||||||
|
*/
|
||||||
|
public static String ensureTraceId() {
|
||||||
|
String traceId = getTraceId();
|
||||||
|
if (traceId == null || traceId.isEmpty()) {
|
||||||
|
traceId = generateTraceIdString();
|
||||||
|
}
|
||||||
|
return traceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定 traceId 覆盖当前线程 MDC(为空则生成)。
|
||||||
|
* 主要用于跨线程/跨进程透传后的落地。
|
||||||
|
*/
|
||||||
|
public static String ensureTraceId(String traceId) {
|
||||||
|
if (traceId == null || traceId.isEmpty()) {
|
||||||
|
return ensureTraceId();
|
||||||
|
}
|
||||||
|
setTraceId(traceId);
|
||||||
|
return traceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装 Runnable:透传提交线程的 MDC,上下文中无 traceId 则补齐;执行完自动清理/还原。
|
||||||
|
*/
|
||||||
|
public static Runnable wrapWithMdc(Runnable task) {
|
||||||
|
final Map<String, String> captured = MDC.getCopyOfContextMap();
|
||||||
|
return () -> {
|
||||||
|
Map<String, String> previous = MDC.getCopyOfContextMap();
|
||||||
|
try {
|
||||||
|
if (captured == null || captured.isEmpty()) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(captured);
|
||||||
|
}
|
||||||
|
ensureTraceId();
|
||||||
|
task.run();
|
||||||
|
} finally {
|
||||||
|
if (previous == null || previous.isEmpty()) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装 Callable:透传提交线程的 MDC,上下文中无 traceId 则补齐;执行完自动清理/还原。
|
||||||
|
*/
|
||||||
|
public static <T> Callable<T> wrapWithMdc(Callable<T> task) {
|
||||||
|
final Map<String, String> captured = MDC.getCopyOfContextMap();
|
||||||
|
return () -> {
|
||||||
|
Map<String, String> previous = MDC.getCopyOfContextMap();
|
||||||
|
try {
|
||||||
|
if (captured == null || captured.isEmpty()) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(captured);
|
||||||
|
}
|
||||||
|
ensureTraceId();
|
||||||
|
return task.call();
|
||||||
|
} finally {
|
||||||
|
if (previous == null || previous.isEmpty()) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除MDC中的TraceId
|
* 清除MDC中的TraceId
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.fastbee.framework.config;
|
||||||
|
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
|
import org.springframework.core.task.TaskDecorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池 MDC 透传装饰器:
|
||||||
|
* - 透传提交线程 MDC
|
||||||
|
* - 兜底补齐 traceId
|
||||||
|
* - 执行结束后还原/清理,避免线程复用污染
|
||||||
|
*/
|
||||||
|
public class MdcTaskDecorator implements TaskDecorator {
|
||||||
|
@Override
|
||||||
|
public Runnable decorate(Runnable runnable) {
|
||||||
|
return TraceIdUtils.wrapWithMdc(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.fastbee.framework.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一 @Scheduled 执行线程池,确保:
|
||||||
|
* - 使用项目自定义的 scheduledExecutorService(已做 MDC 透传与异常打印)
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SchedulingConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Resource(name = "scheduledExecutorService")
|
||||||
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
taskRegistrar.setScheduler(scheduledExecutorService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,13 +1,16 @@
|
|||||||
package com.fastbee.framework.config;
|
package com.fastbee.framework.config;
|
||||||
|
|
||||||
import com.fastbee.common.utils.Threads;
|
import com.fastbee.common.utils.Threads;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.RunnableScheduledFuture;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,8 +39,10 @@ public class ThreadPoolConfig {
|
|||||||
executor.setCorePoolSize(corePoolSize);
|
executor.setCorePoolSize(corePoolSize);
|
||||||
executor.setQueueCapacity(queueCapacity);
|
executor.setQueueCapacity(queueCapacity);
|
||||||
executor.setKeepAliveSeconds(keepAliveSeconds);
|
executor.setKeepAliveSeconds(keepAliveSeconds);
|
||||||
|
executor.setTaskDecorator(new MdcTaskDecorator());
|
||||||
// 线程池对拒绝任务(无线程可用)的处理策略
|
// 线程池对拒绝任务(无线程可用)的处理策略
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
executor.initialize();
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,6 +54,17 @@ public class ThreadPoolConfig {
|
|||||||
return new ScheduledThreadPoolExecutor(corePoolSize,
|
return new ScheduledThreadPoolExecutor(corePoolSize,
|
||||||
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
|
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
|
||||||
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
|
||||||
|
return super.decorateTask(TraceIdUtils.wrapWithMdc(runnable), task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
|
||||||
|
return super.decorateTask(TraceIdUtils.wrapWithMdc(callable), task);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecute(Runnable r, Throwable t) {
|
protected void afterExecute(Runnable r, Throwable t) {
|
||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
|
|||||||
@ -7,14 +7,19 @@ import com.fastbee.common.core.mq.DeviceStatusBo;
|
|||||||
import com.fastbee.common.core.mq.MQSendMessageBo;
|
import com.fastbee.common.core.mq.MQSendMessageBo;
|
||||||
import com.fastbee.common.core.mq.SubDeviceBo;
|
import com.fastbee.common.core.mq.SubDeviceBo;
|
||||||
import com.fastbee.common.core.mq.message.ReportDataBo;
|
import com.fastbee.common.core.mq.message.ReportDataBo;
|
||||||
|
import com.fastbee.common.core.mq.message.DeviceMessage;
|
||||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||||
import com.fastbee.common.enums.DeviceStatus;
|
import com.fastbee.common.enums.DeviceStatus;
|
||||||
|
import com.fastbee.common.core.redis.RedisCache;
|
||||||
|
import com.fastbee.common.utils.StringUtils;
|
||||||
|
import com.fastbee.common.enums.TopicType;
|
||||||
import com.fastbee.iot.cache.IDeviceCache;
|
import com.fastbee.iot.cache.IDeviceCache;
|
||||||
import com.fastbee.iot.data.service.IMqttMessagePublish;
|
import com.fastbee.iot.data.service.IMqttMessagePublish;
|
||||||
import com.fastbee.iot.data.service.IRuleEngine;
|
import com.fastbee.iot.data.service.IRuleEngine;
|
||||||
import com.fastbee.iot.domain.Device;
|
import com.fastbee.iot.domain.Device;
|
||||||
import com.fastbee.iot.domain.Product;
|
import com.fastbee.iot.domain.Product;
|
||||||
import com.fastbee.iot.model.ThingsModels.ThingsModelShadow;
|
import com.fastbee.iot.model.ThingsModels.ThingsModelShadow;
|
||||||
|
import com.fastbee.iot.data.service.IDeviceMessageService;
|
||||||
import com.fastbee.iot.service.IDeviceService;
|
import com.fastbee.iot.service.IDeviceService;
|
||||||
import com.fastbee.iot.service.IProductService;
|
import com.fastbee.iot.service.IProductService;
|
||||||
import com.fastbee.iot.service.ISubGatewayService;
|
import com.fastbee.iot.service.ISubGatewayService;
|
||||||
@ -30,6 +35,7 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备状态消息处理类
|
* 设备状态消息处理类
|
||||||
@ -57,8 +63,20 @@ public class DeviceStatusConsumer {
|
|||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
@Resource
|
@Resource
|
||||||
private ISubGatewayService subGatewayService;
|
private ISubGatewayService subGatewayService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IDeviceMessageService deviceMessageService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisCache redisCache;
|
||||||
|
|
||||||
private SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(2);
|
private SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(2);
|
||||||
|
|
||||||
|
private static final String IMEI_CMD = "AT+IMEI\\r\\n";
|
||||||
|
private static final String ICCID_CMD = "AT+ICCID\\r\\n";
|
||||||
|
private static final int AUTO_FETCH_COOLDOWN_SECONDS = 300;
|
||||||
|
private static final String AUTO_FETCH_KEY_PREFIX = "iot:autoFetch:imeiIccid:";
|
||||||
|
|
||||||
public synchronized void consume(DeviceStatusBo bo) {
|
public synchronized void consume(DeviceStatusBo bo) {
|
||||||
try {
|
try {
|
||||||
List<DeviceStatusBo> list = new ArrayList<>();
|
List<DeviceStatusBo> list = new ArrayList<>();
|
||||||
@ -90,6 +108,10 @@ public class DeviceStatusConsumer {
|
|||||||
}
|
}
|
||||||
/*更新设备状态*/
|
/*更新设备状态*/
|
||||||
deviceCache.updateDeviceStatusCache(statusBo, device);
|
deviceCache.updateDeviceStatusCache(statusBo, device);
|
||||||
|
// 设备首次上线,自动下发 AT 指令获取 IMEI/ICCID(字段为空才下发,并做简单限流)
|
||||||
|
if (status.equals(DeviceStatus.ONLINE)) {
|
||||||
|
autoFetchImeiIccidIfNeeded(device);
|
||||||
|
}
|
||||||
//处理影子模式值
|
//处理影子模式值
|
||||||
this.handlerShadow(device, status);
|
this.handlerShadow(device, status);
|
||||||
//设备上下线执行规则引擎
|
//设备上下线执行规则引擎
|
||||||
@ -107,6 +129,45 @@ public class DeviceStatusConsumer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void autoFetchImeiIccidIfNeeded(Device device) {
|
||||||
|
if (device == null || StringUtils.isEmpty(device.getSerialNumber())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String serialNumber = device.getSerialNumber();
|
||||||
|
|
||||||
|
boolean needImei = StringUtils.isEmpty(device.getImei());
|
||||||
|
boolean needIccid = StringUtils.isEmpty(device.getIccid());
|
||||||
|
if (!needImei && !needIccid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needImei) {
|
||||||
|
String key = AUTO_FETCH_KEY_PREFIX + serialNumber + ":imei";
|
||||||
|
if (!redisCache.containsKey(key)) {
|
||||||
|
redisCache.setCacheObject(key, "1", AUTO_FETCH_COOLDOWN_SECONDS, TimeUnit.SECONDS);
|
||||||
|
sendAtCommand(serialNumber, IMEI_CMD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needIccid) {
|
||||||
|
String key = AUTO_FETCH_KEY_PREFIX + serialNumber + ":iccid";
|
||||||
|
if (!redisCache.containsKey(key)) {
|
||||||
|
redisCache.setCacheObject(key, "1", AUTO_FETCH_COOLDOWN_SECONDS, TimeUnit.SECONDS);
|
||||||
|
sendAtCommand(serialNumber, ICCID_CMD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAtCommand(String serialNumber, String command) {
|
||||||
|
DeviceMessage msg = new DeviceMessage();
|
||||||
|
msg.setSerialNumber(serialNumber);
|
||||||
|
msg.setTopicName(TopicType.FUNCTION_GET.getTopicSuffix());
|
||||||
|
msg.setMessage(command);
|
||||||
|
msg.setDataType("ascii");
|
||||||
|
deviceMessageService.messagePost(msg);
|
||||||
|
log.info("自动下发 AT 指令获取信息, serialNumber={}, cmd={}", serialNumber, command);
|
||||||
|
}
|
||||||
|
|
||||||
private void handlerShadow(Device device, DeviceStatus status) {
|
private void handlerShadow(Device device, DeviceStatus status) {
|
||||||
//获取设备协议编码
|
//获取设备协议编码
|
||||||
DeviceAndProtocol dp = deviceService.selectProtocolBySerialNumber(device.getSerialNumber());
|
DeviceAndProtocol dp = deviceService.selectProtocolBySerialNumber(device.getSerialNumber());
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.DeviceReportBo;
|
import com.fastbee.common.core.mq.DeviceReportBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.DeviceOtherMsgConsumer;
|
import com.fastbee.iot.data.consumer.DeviceOtherMsgConsumer;
|
||||||
import com.fastbee.mq.queue.DeviceOtherQueue;
|
import com.fastbee.mq.queue.DeviceOtherQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -26,9 +27,13 @@ public class DeviceOtherListen {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
DeviceReportBo reportBo = DeviceOtherQueue.take();
|
DeviceReportBo reportBo = DeviceOtherQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
otherMsgConsumer.consume(reportBo);
|
otherMsgConsumer.consume(reportBo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>emq数据转发异常");
|
log.error("=>emq数据转发异常");
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.fastbee.common.constant.FastBeeConstant;
|
|||||||
import com.fastbee.iot.data.consumer.DevicePropFetchConsumer;
|
import com.fastbee.iot.data.consumer.DevicePropFetchConsumer;
|
||||||
import com.fastbee.iot.model.modbus.ModbusPollJob;
|
import com.fastbee.iot.model.modbus.ModbusPollJob;
|
||||||
import com.fastbee.mq.queue.DevicePropFetchQueue;
|
import com.fastbee.mq.queue.DevicePropFetchQueue;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
@ -27,9 +28,14 @@ public class DevicePropFetchListen {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
ModbusPollJob take = DevicePropFetchQueue.take();
|
ModbusPollJob take = DevicePropFetchQueue.take();
|
||||||
|
// 队列消费是典型的异步边界:每条消息独立生成 traceId,避免线程复用导致 traceId 串线
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
devicePropFetchConsumer.consume(take);
|
devicePropFetchConsumer.consume(take);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>设备属性获取异常", e);
|
log.error("=>设备属性获取异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.DeviceReportBo;
|
import com.fastbee.common.core.mq.DeviceReportBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.DeviceReplyMsgConsumer;
|
import com.fastbee.iot.data.consumer.DeviceReplyMsgConsumer;
|
||||||
import com.fastbee.mq.queue.DeviceReplyQueue;
|
import com.fastbee.mq.queue.DeviceReplyQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -27,10 +28,14 @@ public class DeviceReplyListen {
|
|||||||
try {
|
try {
|
||||||
/*读队列消息*/
|
/*读队列消息*/
|
||||||
DeviceReportBo reportBo = DeviceReplyQueue.take();
|
DeviceReportBo reportBo = DeviceReplyQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
/*处理消息*/
|
/*处理消息*/
|
||||||
deviceReplyMsgHandler.consume(reportBo);
|
deviceReplyMsgHandler.consume(reportBo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>设备回调消息监听异常", e);
|
log.error("=>设备回调消息监听异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.DeviceReportBo;
|
import com.fastbee.common.core.mq.DeviceReportBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.DeviceReportMsgConsumer;
|
import com.fastbee.iot.data.consumer.DeviceReportMsgConsumer;
|
||||||
import com.fastbee.mq.queue.DeviceReportQueue;
|
import com.fastbee.mq.queue.DeviceReportQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -27,10 +28,14 @@ public class DeviceReportListen {
|
|||||||
try {
|
try {
|
||||||
/*取出数据*/
|
/*取出数据*/
|
||||||
DeviceReportBo reportBo = DeviceReportQueue.take();
|
DeviceReportBo reportBo = DeviceReportQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
/*处理数据*/
|
/*处理数据*/
|
||||||
reportMsgConsumer.consume(reportBo);
|
reportMsgConsumer.consume(reportBo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>设备上报数据监听异常", e);
|
log.error("=>设备上报数据监听异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.DeviceStatusBo;
|
import com.fastbee.common.core.mq.DeviceStatusBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.DeviceStatusConsumer;
|
import com.fastbee.iot.data.consumer.DeviceStatusConsumer;
|
||||||
import com.fastbee.mq.queue.DeviceStatusQueue;
|
import com.fastbee.mq.queue.DeviceStatusQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -23,13 +24,17 @@ public class DeviceStatusListen {
|
|||||||
|
|
||||||
@Async(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK)
|
@Async(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK)
|
||||||
public void listen() {
|
public void listen() {
|
||||||
try {
|
while (true) {
|
||||||
while (true) {
|
try {
|
||||||
DeviceStatusBo status = DeviceStatusQueue.take();
|
DeviceStatusBo status = DeviceStatusQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
deviceStatusConsumer.consume(status);
|
deviceStatusConsumer.consume(status);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("设备状态监听错误", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("设备状态监听错误", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.DeviceTestReportBo;
|
import com.fastbee.common.core.mq.DeviceTestReportBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.DeviceTestConsumer;
|
import com.fastbee.iot.data.consumer.DeviceTestConsumer;
|
||||||
import com.fastbee.mq.queue.DeviceTestQueue;
|
import com.fastbee.mq.queue.DeviceTestQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -25,10 +26,14 @@ public class DeviceTestListen {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
DeviceTestReportBo take = DeviceTestQueue.take();
|
DeviceTestReportBo take = DeviceTestQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
|
|
||||||
deviceTestConsumer.consume(take);
|
deviceTestConsumer.consume(take);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>emq数据转发异常");
|
log.error("=>emq数据转发异常");
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.MQSendMessageBo;
|
import com.fastbee.common.core.mq.MQSendMessageBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.consumer.FunctionInvokeConsumer;
|
import com.fastbee.iot.data.consumer.FunctionInvokeConsumer;
|
||||||
import com.fastbee.mq.queue.FunctionInvokeQueue;
|
import com.fastbee.mq.queue.FunctionInvokeQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -26,9 +27,13 @@ public class FunctionInvokeListen {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
MQSendMessageBo sendBo = FunctionInvokeQueue.take();
|
MQSendMessageBo sendBo = FunctionInvokeQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
functionInvokeConsumer.handler(sendBo);
|
functionInvokeConsumer.handler(sendBo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>下发服务消费异常", e);
|
log.error("=>下发服务消费异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.fastbee.common.constant.FastBeeConstant;
|
|||||||
import com.fastbee.common.core.domain.entity.SysMenu;
|
import com.fastbee.common.core.domain.entity.SysMenu;
|
||||||
import com.fastbee.common.core.mq.ota.OtaUpgradeDelayTask;
|
import com.fastbee.common.core.mq.ota.OtaUpgradeDelayTask;
|
||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.service.IOtaUpgradeService;
|
import com.fastbee.iot.data.service.IOtaUpgradeService;
|
||||||
import com.fastbee.mq.queue.DelayUpgradeQueue;
|
import com.fastbee.mq.queue.DelayUpgradeQueue;
|
||||||
import com.fastbee.system.service.ISysMenuService;
|
import com.fastbee.system.service.ISysMenuService;
|
||||||
@ -47,6 +48,8 @@ public class UpGradeListener implements ApplicationRunner {
|
|||||||
try {
|
try {
|
||||||
OtaUpgradeDelayTask task = DelayUpgradeQueue.task();
|
OtaUpgradeDelayTask task = DelayUpgradeQueue.task();
|
||||||
if (StringUtils.isNotNull(task)) {
|
if (StringUtils.isNotNull(task)) {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
Date startTime = task.getStartTime();
|
Date startTime = task.getStartTime();
|
||||||
otaUpgradeService.upgrade(task);
|
otaUpgradeService.upgrade(task);
|
||||||
log.info("=>开始OTA升级时间{}", startTime);
|
log.info("=>开始OTA升级时间{}", startTime);
|
||||||
@ -54,6 +57,8 @@ public class UpGradeListener implements ApplicationRunner {
|
|||||||
continue;
|
continue;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("=>OTA升级监听异常", e);
|
log.error("=>OTA升级监听异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fastbee.iot.data.listen;
|
|||||||
|
|
||||||
import com.fastbee.common.constant.FastBeeConstant;
|
import com.fastbee.common.constant.FastBeeConstant;
|
||||||
import com.fastbee.common.core.mq.ota.OtaUpgradeBo;
|
import com.fastbee.common.core.mq.ota.OtaUpgradeBo;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.iot.data.service.IMqttMessagePublish;
|
import com.fastbee.iot.data.service.IMqttMessagePublish;
|
||||||
import com.fastbee.mq.queue.OtaUpgradeQueue;
|
import com.fastbee.mq.queue.OtaUpgradeQueue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -28,10 +29,14 @@ public class UpgradeListen {
|
|||||||
try {
|
try {
|
||||||
/*获取队列中的OTA升级消息*/
|
/*获取队列中的OTA升级消息*/
|
||||||
OtaUpgradeBo upgradeBo = OtaUpgradeQueue.take();
|
OtaUpgradeBo upgradeBo = OtaUpgradeQueue.take();
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
// OTA升级处理
|
// OTA升级处理
|
||||||
functionSendService.upGradeOTA(upgradeBo);
|
functionSendService.upGradeOTA(upgradeBo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("->OTA消息监听异常", e);
|
log.error("->OTA消息监听异常", e);
|
||||||
|
} finally {
|
||||||
|
TraceIdUtils.clearTraceId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import com.fastbee.common.exception.ServiceException;
|
|||||||
import com.fastbee.common.utils.DateUtils;
|
import com.fastbee.common.utils.DateUtils;
|
||||||
import com.fastbee.common.utils.SecurityUtils;
|
import com.fastbee.common.utils.SecurityUtils;
|
||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import com.fastbee.common.utils.spring.SpringUtils;
|
import com.fastbee.common.utils.spring.SpringUtils;
|
||||||
import com.fastbee.iot.data.service.IFunctionInvoke;
|
import com.fastbee.iot.data.service.IFunctionInvoke;
|
||||||
import com.fastbee.iot.data.service.IRuleEngine;
|
import com.fastbee.iot.data.service.IRuleEngine;
|
||||||
@ -91,11 +92,12 @@ public class SceneContext {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private boolean process(String json) throws InterruptedException {
|
private boolean process(String json) throws InterruptedException {
|
||||||
|
// 场景执行很多时候不在 Web 请求线程内,这里兜底补齐 traceId
|
||||||
|
TraceIdUtils.ensureTraceId();
|
||||||
ScriptTemplate scriptTemplate = JSON.parseObject(json, ScriptTemplate.class);
|
ScriptTemplate scriptTemplate = JSON.parseObject(json, ScriptTemplate.class);
|
||||||
String requestId = "scene/" + scriptTemplate.getChainName();
|
String requestId = "scene/" + scriptTemplate.getChainName();
|
||||||
scene_logger.info("[{}]=====+>场景联动规则开始执行!", requestId);
|
scene_logger.info("[{}]=====+>场景联动规则开始执行!", requestId);
|
||||||
scene_logger.info("[{}]=====+>规则引擎脚本配置:{},规则引擎上下文:{}", requestId, scriptTemplate, this);
|
scene_logger.info("[{}]=====+>规则引擎脚本配置:{},规则引擎上下文:{}", requestId, JSON.toJSONString(scriptTemplate), JSON.toJSONString(this));
|
||||||
// MDC.put("id", scriptTemplate.getChainName());
|
// MDC.put("id", scriptTemplate.getChainName());
|
||||||
// 触发器
|
// 触发器
|
||||||
if (scriptTemplate.getPurpose() == 2) {
|
if (scriptTemplate.getPurpose() == 2) {
|
||||||
@ -377,7 +379,7 @@ public class SceneContext {
|
|||||||
// 默认上线执行告警恢复 在延迟匹配周期内不告警
|
// 默认上线执行告警恢复 在延迟匹配周期内不告警
|
||||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
int delayTime = scriptTemplate.getCheckdelay() > 0 ? scriptTemplate.getCheckdelay() : scriptTemplate.getDelay();
|
int delayTime = scriptTemplate.getCheckdelay() > 0 ? scriptTemplate.getCheckdelay() : scriptTemplate.getDelay();
|
||||||
executor.schedule(() -> {
|
executor.schedule(TraceIdUtils.wrapWithMdc(() -> {
|
||||||
// 设备未上线,则执行告警任务
|
// 设备未上线,则执行告警任务
|
||||||
if (scriptTemplate.getSource() == 4) {
|
if (scriptTemplate.getSource() == 4) {
|
||||||
// 告警
|
// 告警
|
||||||
@ -386,7 +388,7 @@ public class SceneContext {
|
|||||||
// 下发指令
|
// 下发指令
|
||||||
this.send(scriptTemplate);
|
this.send(scriptTemplate);
|
||||||
}
|
}
|
||||||
}, delayTime, TimeUnit.SECONDS);
|
}), delayTime, TimeUnit.SECONDS);
|
||||||
scene_logger.info("[{}]=====+>延时执行告警任务:{}", requestId, key);
|
scene_logger.info("[{}]=====+>延时执行告警任务:{}", requestId, key);
|
||||||
ruleService.addCheckTask(key, executor);
|
ruleService.addCheckTask(key, executor);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.fastbee.record.config;
|
||||||
|
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.RunnableScheduledFuture;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* record 模块自身的 @Scheduled 配置(该模块 ComponentScan 不包含 fastbee-framework)。
|
||||||
|
* 统一使用带 MDC 透传的线程池执行定时任务。
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SchedulingConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Bean(name = "recordScheduledExecutorService")
|
||||||
|
public ScheduledExecutorService recordScheduledExecutorService() {
|
||||||
|
int corePoolSize = Math.max(2, Runtime.getRuntime().availableProcessors());
|
||||||
|
return new ScheduledThreadPoolExecutor(corePoolSize,
|
||||||
|
new BasicThreadFactory.Builder().namingPattern("record-schedule-pool-%d").daemon(true).build(),
|
||||||
|
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
|
||||||
|
return super.decorateTask(TraceIdUtils.wrapWithMdc(runnable), task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
|
||||||
|
return super.decorateTask(TraceIdUtils.wrapWithMdc(callable), task);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
taskRegistrar.setScheduler(recordScheduledExecutorService());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package com.fastbee.record.config;
|
package com.fastbee.record.config;
|
||||||
|
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
@ -48,6 +49,7 @@ public class ThreadPoolTaskConfig {
|
|||||||
executor.setQueueCapacity(queueCapacity);
|
executor.setQueueCapacity(queueCapacity);
|
||||||
executor.setKeepAliveSeconds(keepAliveTime);
|
executor.setKeepAliveSeconds(keepAliveTime);
|
||||||
executor.setThreadNamePrefix(threadNamePrefix);
|
executor.setThreadNamePrefix(threadNamePrefix);
|
||||||
|
executor.setTaskDecorator(TraceIdUtils::wrapWithMdc);
|
||||||
|
|
||||||
// 线程池对拒绝任务的处理策略
|
// 线程池对拒绝任务的处理策略
|
||||||
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
|
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.fastbee.sip.conf;
|
package com.fastbee.sip.conf;
|
||||||
|
|
||||||
|
import com.fastbee.common.utils.TraceIdUtils;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
@ -25,6 +26,7 @@ public class ThreadPoolTaskConfig {
|
|||||||
executor.setQueueCapacity(queueCapacity);
|
executor.setQueueCapacity(queueCapacity);
|
||||||
executor.setKeepAliveSeconds(keepAliveTime);
|
executor.setKeepAliveSeconds(keepAliveTime);
|
||||||
executor.setThreadNamePrefix(threadNamePrefix);
|
executor.setThreadNamePrefix(threadNamePrefix);
|
||||||
|
executor.setTaskDecorator(TraceIdUtils::wrapWithMdc);
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
executor.initialize();
|
executor.initialize();
|
||||||
return executor;
|
return executor;
|
||||||
|
|||||||
@ -227,6 +227,18 @@ public class Device extends BaseEntity {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String transport;
|
private String transport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMEI(蜂窝模块设备标识)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("IMEI")
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICCID(SIM卡标识)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("ICCID")
|
||||||
|
private String iccid;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
@ApiModelProperty("机构id")
|
@ApiModelProperty("机构id")
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
|
|||||||
@ -44,6 +44,16 @@ public class DeviceAllShortOutput {
|
|||||||
*/
|
*/
|
||||||
private String serialNumber;
|
private String serialNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMEI(蜂窝模块设备标识)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICCID(SIM卡标识)
|
||||||
|
*/
|
||||||
|
private String iccid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 固件版本
|
* 固件版本
|
||||||
*/
|
*/
|
||||||
@ -217,6 +227,22 @@ public class DeviceAllShortOutput {
|
|||||||
this.serialNumber = serialNumber;
|
this.serialNumber = serialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getImei() {
|
||||||
|
return imei;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImei(String imei) {
|
||||||
|
this.imei = imei;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIccid() {
|
||||||
|
return iccid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIccid(String iccid) {
|
||||||
|
this.iccid = iccid;
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal getFirmwareVersion() {
|
public BigDecimal getFirmwareVersion() {
|
||||||
return firmwareVersion;
|
return firmwareVersion;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,16 @@ public class DeviceShortOutput {
|
|||||||
*/
|
*/
|
||||||
@Excel(name = "设备编号")
|
@Excel(name = "设备编号")
|
||||||
private String serialNumber;
|
private String serialNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMEI(蜂窝模块设备标识)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICCID(SIM卡标识)
|
||||||
|
*/
|
||||||
|
private String iccid;
|
||||||
/**
|
/**
|
||||||
* 固件版本
|
* 固件版本
|
||||||
*/
|
*/
|
||||||
@ -396,6 +406,22 @@ public class DeviceShortOutput {
|
|||||||
this.serialNumber = serialNumber;
|
this.serialNumber = serialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getImei() {
|
||||||
|
return imei;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImei(String imei) {
|
||||||
|
this.imei = imei;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIccid() {
|
||||||
|
return iccid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIccid(String iccid) {
|
||||||
|
this.iccid = iccid;
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal getFirmwareVersion() {
|
public BigDecimal getFirmwareVersion() {
|
||||||
return firmwareVersion;
|
return firmwareVersion;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -303,7 +303,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
}
|
}
|
||||||
device.setUpdateTime(DateUtils.getNowDate());
|
device.setUpdateTime(DateUtils.getNowDate());
|
||||||
// 未激活状态,可以修改产品以及物模型值
|
// 未激活状态,可以修改产品以及物模型值
|
||||||
if (device.getStatus() == 1) {
|
if (Integer.valueOf(1).equals(device.getStatus())) {
|
||||||
// 缓存设备状态(物模型值)
|
// 缓存设备状态(物模型值)
|
||||||
itslValueCache.addCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
|
itslValueCache.addCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="transport" column="transport" />
|
<result property="transport" column="transport" />
|
||||||
<result property="guid" column="guid" />
|
<result property="guid" column="guid" />
|
||||||
<result property="protocolCode" column="protocol_code" />
|
<result property="protocolCode" column="protocol_code" />
|
||||||
|
<result property="imei" column="imei" />
|
||||||
|
<result property="iccid" column="iccid" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<resultMap type="com.fastbee.iot.model.DeviceShortOutput" id="DeviceShortResult">
|
<resultMap type="com.fastbee.iot.model.DeviceShortOutput" id="DeviceShortResult">
|
||||||
@ -64,6 +66,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="protocolCode" column="protocol_code"/>
|
<result property="protocolCode" column="protocol_code"/>
|
||||||
<result property="transport" column="transport" />
|
<result property="transport" column="transport" />
|
||||||
<result property="guid" column="guid" />
|
<result property="guid" column="guid" />
|
||||||
|
<result property="imei" column="imei" />
|
||||||
|
<result property="iccid" column="iccid" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<resultMap type="com.fastbee.iot.model.DeviceAllShortOutput" id="DeviceAllShortResult">
|
<resultMap type="com.fastbee.iot.model.DeviceAllShortOutput" id="DeviceAllShortResult">
|
||||||
@ -84,6 +88,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="latitude" column="latitude" />
|
<result property="latitude" column="latitude" />
|
||||||
<result property="isOwner" column="is_owner" />
|
<result property="isOwner" column="is_owner" />
|
||||||
<result property="subDeviceCount" column="sub_device_count"/>
|
<result property="subDeviceCount" column="sub_device_count"/>
|
||||||
|
<result property="imei" column="imei" />
|
||||||
|
<result property="iccid" column="iccid" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<resultMap type="com.fastbee.iot.model.UserAndTenant" id="UserAndTenantResult">
|
<resultMap type="com.fastbee.iot.model.UserAndTenant" id="UserAndTenantResult">
|
||||||
@ -187,6 +193,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
update_time,
|
update_time,
|
||||||
img_url,
|
img_url,
|
||||||
summary,
|
summary,
|
||||||
|
imei,
|
||||||
|
iccid,
|
||||||
remark,
|
remark,
|
||||||
slave_id
|
slave_id
|
||||||
from iot_device
|
from iot_device
|
||||||
@ -208,6 +216,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
location_way,
|
location_way,
|
||||||
things_model_value,
|
things_model_value,
|
||||||
active_time,
|
active_time,
|
||||||
|
imei,
|
||||||
|
iccid,
|
||||||
img_url,
|
img_url,
|
||||||
slave_id
|
slave_id
|
||||||
from iot_device
|
from iot_device
|
||||||
@ -434,7 +444,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
select d.device_id, d.device_name, d.product_id, p.product_name,p.device_type, d.tenant_id, d.tenant_name,
|
select d.device_id, d.device_name, d.product_id, p.product_name,p.device_type, d.tenant_id, d.tenant_name,
|
||||||
d.serial_number, d.firmware_version,d.wireless_version, d.status, d.rssi,d.is_shadow,d.is_simulate ,d.location_way,d.things_model_value,
|
d.serial_number, d.firmware_version,d.wireless_version, d.status, d.rssi,d.is_shadow,d.is_simulate ,d.location_way,d.things_model_value,
|
||||||
d.network_address, d.network_ip, d.longitude, d.latitude, d.active_time, d.create_time, d.update_time,
|
d.network_address, d.network_ip, d.longitude, d.latitude, d.active_time, d.create_time, d.update_time,
|
||||||
d.img_url,d.summary,d.remark,p.guid, p.transport, p.protocol_code from iot_device d
|
d.img_url,d.summary,d.imei,d.iccid,d.remark,p.guid, p.transport, p.protocol_code from iot_device d
|
||||||
left join iot_product p on p.product_id=d.product_id
|
left join iot_product p on p.product_id=d.product_id
|
||||||
where device_id = #{deviceId}
|
where device_id = #{deviceId}
|
||||||
</select>
|
</select>
|
||||||
@ -657,6 +667,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="remark != null">remark = #{remark},</if>
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
<if test="imgUrl != null">img_url = #{imgUrl},</if>
|
<if test="imgUrl != null">img_url = #{imgUrl},</if>
|
||||||
<if test="summary != null">summary = #{summary},</if>
|
<if test="summary != null">summary = #{summary},</if>
|
||||||
|
<if test="imei != null">imei = #{imei},</if>
|
||||||
|
<if test="iccid != null">iccid = #{iccid},</if>
|
||||||
<if test="slaveId != null">slave_id = #{slaveId},</if>
|
<if test="slaveId != null">slave_id = #{slaveId},</if>
|
||||||
</trim>
|
</trim>
|
||||||
where device_id = #{deviceId}
|
where device_id = #{deviceId}
|
||||||
@ -718,6 +730,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="imgUrl != null">img_url = #{imgUrl},</if>
|
<if test="imgUrl != null">img_url = #{imgUrl},</if>
|
||||||
<if test="summary != null">summary = #{summary},</if>
|
<if test="summary != null">summary = #{summary},</if>
|
||||||
<if test="gwDevCode != null">gw_dev_code = #{gwDevCode},</if>
|
<if test="gwDevCode != null">gw_dev_code = #{gwDevCode},</if>
|
||||||
|
<if test="imei != null">imei = #{imei},</if>
|
||||||
|
<if test="iccid != null">iccid = #{iccid},</if>
|
||||||
</trim>
|
</trim>
|
||||||
where serial_number = #{serialNumber}
|
where serial_number = #{serialNumber}
|
||||||
</update>
|
</update>
|
||||||
|
|||||||
@ -21,6 +21,39 @@
|
|||||||
<el-button type="success" size="mini" style="float: right" @click="getLatestFirmware(deviceInfo.deviceId)" :disabled="deviceInfo.status != 3">{{ $t('device.running-status.866086-2') }}</el-button>
|
<el-button type="success" size="mini" style="float: right" @click="getLatestFirmware(deviceInfo.deviceId)" :disabled="deviceInfo.status != 3">{{ $t('device.running-status.866086-2') }}</el-button>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<!-- IMEI / ICCID(蜂窝信息) -->
|
||||||
|
<el-descriptions-item :labelStyle="statusColor">
|
||||||
|
<template slot="label">
|
||||||
|
<i class="el-icon-postcard"></i>
|
||||||
|
IMEI
|
||||||
|
</template>
|
||||||
|
<div class="cell-flex">
|
||||||
|
<el-input v-model="deviceInfo.imei" size="mini" placeholder="请输入IMEI" style="max-width: 260px;" @keyup.enter.native="saveImeiIccid('imei')" />
|
||||||
|
<el-popover placement="bottom" width="360" trigger="click" popper-class="atcmd-popover">
|
||||||
|
<div class="atcmd-title">编辑下发指令</div>
|
||||||
|
<el-input v-model="imeiCmd" size="mini" placeholder="例如:AT+IMEI\\r\\n" />
|
||||||
|
<el-button slot="reference" size="mini" icon="el-icon-edit" title="编辑指令"></el-button>
|
||||||
|
</el-popover>
|
||||||
|
<el-button type="primary" size="mini" :disabled="deviceInfo.status != 3" @click="sendAt('imei')" :loading="imeiLoading" title="默认指令:AT+IMEI\r\n">从设备读取</el-button>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :labelStyle="statusColor">
|
||||||
|
<template slot="label">
|
||||||
|
<i class="el-icon-postcard"></i>
|
||||||
|
ICCID
|
||||||
|
</template>
|
||||||
|
<div class="cell-flex">
|
||||||
|
<el-input v-model="deviceInfo.iccid" size="mini" placeholder="请输入ICCID" style="max-width: 260px;" @keyup.enter.native="saveImeiIccid('iccid')"/>
|
||||||
|
<el-popover placement="bottom" width="360" trigger="click" popper-class="atcmd-popover">
|
||||||
|
<div class="atcmd-title">编辑下发指令</div>
|
||||||
|
<el-input v-model="iccidCmd" size="mini" placeholder="例如:AT+ICCID\\r\\n" />
|
||||||
|
<el-button slot="reference" size="mini" icon="el-icon-edit" title="编辑指令"></el-button>
|
||||||
|
</el-popover>
|
||||||
|
<el-button type="primary" size="mini" :disabled="deviceInfo.status != 3" @click="sendAt('iccid')" :loading="iccidLoading" title="默认指令:AT+ICCID\r\n">从设备读取</el-button>
|
||||||
|
</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
<!-- 设备物模型-->
|
<!-- 设备物模型-->
|
||||||
<el-descriptions-item v-for="(item, index) in deviceInfo.thingsModels" :key="index" :labelStyle="statusColor">
|
<el-descriptions-item v-for="(item, index) in deviceInfo.thingsModels" :key="index" :labelStyle="statusColor">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
@ -512,6 +545,8 @@
|
|||||||
import { getLatestFirmware } from '@/api/iot/firmware';
|
import { getLatestFirmware } from '@/api/iot/firmware';
|
||||||
|
|
||||||
import { serviceInvoke } from '@/api/iot/runstatus';
|
import { serviceInvoke } from '@/api/iot/runstatus';
|
||||||
|
import { messagePost } from '@/api/iot/mqttTest';
|
||||||
|
import { getDevice, updateDevice } from '@/api/iot/device';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'running-status',
|
name: 'running-status',
|
||||||
@ -581,6 +616,12 @@ export default {
|
|||||||
],
|
],
|
||||||
resizeObserver: null,
|
resizeObserver: null,
|
||||||
remoteCommand: {},
|
remoteCommand: {},
|
||||||
|
imeiCmd: 'AT+IMEI\\r\\n',
|
||||||
|
iccidCmd: 'AT+ICCID\\r\\n',
|
||||||
|
imeiLoading: false,
|
||||||
|
iccidLoading: false,
|
||||||
|
saveLoadingImei: false,
|
||||||
|
saveLoadingIccid: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -600,6 +641,73 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
async refreshDeviceBaseInfo() {
|
||||||
|
if (!this.deviceInfo || !this.deviceInfo.deviceId) return;
|
||||||
|
const res = await getDevice(this.deviceInfo.deviceId);
|
||||||
|
if (res && res.code === 200 && res.data) {
|
||||||
|
// 只刷新这两个字段,避免影响运行态数据
|
||||||
|
this.deviceInfo.imei = res.data.imei;
|
||||||
|
this.deviceInfo.iccid = res.data.iccid;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async sendAt(type) {
|
||||||
|
try {
|
||||||
|
const cmd = type === 'imei' ? this.imeiCmd : this.iccidCmd;
|
||||||
|
if (!cmd) {
|
||||||
|
this.$message({ type: 'warning', message: '指令不能为空' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'imei') this.imeiLoading = true;
|
||||||
|
if (type === 'iccid') this.iccidLoading = true;
|
||||||
|
|
||||||
|
await messagePost({
|
||||||
|
message: cmd,
|
||||||
|
serialNumber: this.deviceInfo.serialNumber,
|
||||||
|
topicName: '/function/get',
|
||||||
|
dataType: 'ascii',
|
||||||
|
});
|
||||||
|
this.$message({ type: 'success', message: '已下发指令,等待设备回复解析…' });
|
||||||
|
|
||||||
|
// 后端收到回复后会自动解析并写入数据库,这里做一次轻量轮询刷新
|
||||||
|
setTimeout(() => this.refreshDeviceBaseInfo(), 1200);
|
||||||
|
setTimeout(() => this.refreshDeviceBaseInfo(), 2500);
|
||||||
|
} catch (e) {
|
||||||
|
this.$message({ type: 'error', message: e && e.message ? e.message : '指令下发失败' });
|
||||||
|
} finally {
|
||||||
|
this.imeiLoading = false;
|
||||||
|
this.iccidLoading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveImeiIccid(type) {
|
||||||
|
try {
|
||||||
|
if (!this.deviceInfo || !this.deviceInfo.deviceId) return;
|
||||||
|
if (type === 'imei') this.saveLoadingImei = true;
|
||||||
|
if (type === 'iccid') this.saveLoadingIccid = true;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
deviceId: this.deviceInfo.deviceId,
|
||||||
|
serialNumber: this.deviceInfo.serialNumber,
|
||||||
|
};
|
||||||
|
if (type === 'imei') payload.imei = this.deviceInfo.imei;
|
||||||
|
if (type === 'iccid') payload.iccid = this.deviceInfo.iccid;
|
||||||
|
|
||||||
|
const res = await updateDevice(payload);
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
this.$message({ type: 'success', message: '保存成功' });
|
||||||
|
await this.refreshDeviceBaseInfo();
|
||||||
|
} else {
|
||||||
|
this.$message({ type: 'error', message: (res && res.msg) || '保存失败' });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.$message({ type: 'error', message: e && e.message ? e.message : '保存失败' });
|
||||||
|
} finally {
|
||||||
|
this.saveLoadingImei = false;
|
||||||
|
this.saveLoadingIccid = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initResizeObserver() {
|
initResizeObserver() {
|
||||||
if (this.resizeObserver) return;
|
if (this.resizeObserver) return;
|
||||||
if (typeof window.ResizeObserver !== 'function') return;
|
if (typeof window.ResizeObserver !== 'function') return;
|
||||||
@ -1083,6 +1191,20 @@ export default {
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cell-flex {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.atcmd-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.monitor-grid-wrap {
|
.monitor-grid-wrap {
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
padding: 20px 10px;
|
padding: 20px 10px;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user