mirror of
https://gitee.com/iteaj/iboot.git
synced 2026-08-30 17:20:20 +08:00
!6 feat: 数据源采集配置,新增支持cron和定时采集自定义
Merge pull request !6 from Stuil/dev_jdk17
This commit is contained in:
+16
-16
@@ -22,7 +22,7 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class CollectGroupTask implements Runnable {
|
||||
public class CollectGroupTask implements Runnable{
|
||||
|
||||
private DeviceGroup group;
|
||||
private List<ModelApi> apis;
|
||||
@@ -40,7 +40,7 @@ public class CollectGroupTask implements Runnable {
|
||||
public void run() {
|
||||
// 没有任何采集接口, 放弃采集任务
|
||||
if(this.apis == null || this.apis.isEmpty()) {
|
||||
IotLogger.warn(source, "-", "放弃采集任务 没有任何采集接口 - 设备组: {}", group.getName());
|
||||
IotLogger.warn(source,"-","放弃采集任务 没有任何采集接口 - 设备组: {}", group.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,19 +58,19 @@ public class CollectGroupTask implements Runnable {
|
||||
if(device.getStatus() == DeviceStatus.offline) {
|
||||
if(device.getType() == DeviceType.Gateway) {
|
||||
IotLogger.warn(source, device.getUid(), "放弃设备采集 设备不在线 - 设备组: {} - 设备编号: {}"
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
continue;
|
||||
} else if(device.getType() == DeviceType.Child) {
|
||||
RealtimeStatus parent = cacheManager.get(device.getProtocolCode(), device.getParentDeviceSn());
|
||||
if(parent != null) {
|
||||
if(parent.getStatus() == DeviceStatus.offline) {
|
||||
IotLogger.warn(source, device.getUid(), "放弃设备采集 网关设备不在线 - 设备组: {} - 设备编号: {}"
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
IotLogger.warn(source, device.getUid(), "放弃设备采集 父设备不存在 - 设备组: {} - 设备编号: {}"
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
, group.getName(), device.buildDeviceKey());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class CollectGroupTask implements Runnable {
|
||||
if(prevParentDeviceSn != null && ProtocolCodes.isModbus(device.getProtocolCode())) {
|
||||
// 同一台网关设备的采集时间需要有一定间隔(防止网关设备性能差导致采集失败)
|
||||
if(prevParentDeviceSn.equals(device.getParentDeviceSn())) {
|
||||
Thread.sleep(1000); // 休眠1秒
|
||||
Thread.sleep(200); // 休眠1秒
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,14 +94,14 @@ public class CollectGroupTask implements Runnable {
|
||||
prevParentDeviceSn = device.getParentDeviceSn();
|
||||
}
|
||||
} catch (ProtocolInvokeException e) {
|
||||
IotLogger.error(source, device.getUid(), "接口采集执行异常 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
IotLogger.error(source, device.getUid(),"接口采集执行异常 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
} catch (ServiceException e) {
|
||||
IotLogger.error(source, device.getUid(), "接口采集执行错误 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
IotLogger.error(source, device.getUid(),"接口采集执行错误 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
} catch (Exception e) {
|
||||
IotLogger.error(source, device.getUid(), "接口采集未知异常 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
IotLogger.error(source, device.getUid(),"接口采集未知异常 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class CollectGroupTask implements Runnable {
|
||||
try {
|
||||
listener.finished(info);
|
||||
} catch (Exception e) {
|
||||
IotLogger.error(source, "-", "采集事件完成发布异常 {} - 设备组: {}", e.getMessage(), source.getName(), group.getName(), e);
|
||||
IotLogger.error(source,"-","采集事件完成发布异常 {} - 设备组: {}", e.getMessage(), source.getName(), group.getName(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -128,10 +128,10 @@ public class CollectGroupTask implements Runnable {
|
||||
} else {
|
||||
if(retry) {
|
||||
IotLogger.warn(source, device.getUid(), "采集重试失败 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", result.getReason()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect());
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect());
|
||||
} else {
|
||||
IotLogger.warn(source, device.getUid(), "采集失败 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", result.getReason()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect());
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect());
|
||||
}
|
||||
|
||||
// 发布采集的数据
|
||||
@@ -150,7 +150,7 @@ public class CollectGroupTask implements Runnable {
|
||||
item.supplier(source, group, deviceInfo);
|
||||
} catch (Exception e) {
|
||||
IotLogger.error(source, device.getUid(), "采集事件实时发布异常 {} - 设备组: {} - 设备编号: {} - 接口: {}/{}", e.getMessage()
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
, group.getName(), device.buildDeviceKey(), api.getCode(), api.getDirect(), e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+86
-48
@@ -19,6 +19,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -30,12 +31,15 @@ public class EventSourceCollectService implements ApplicationReadyListener {
|
||||
private final IBootThreadManger threadManger;
|
||||
private final IDeviceGroupService deviceGroupService;
|
||||
private final IEventSourceService eventSourceService;
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final Map<Long, ScheduledFuture> futures = new ConcurrentHashMap<>(128);
|
||||
|
||||
public EventSourceCollectService(IotCacheManager cacheManager
|
||||
, IBootThreadManger threadManger, IDeviceGroupService deviceGroupService
|
||||
, IEventSourceService eventSourceService) {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final Map<Long, ScheduledFuture<?>> futures = new ConcurrentHashMap<>(128);
|
||||
|
||||
public EventSourceCollectService(IotCacheManager cacheManager,
|
||||
IBootThreadManger threadManger,
|
||||
IDeviceGroupService deviceGroupService,
|
||||
IEventSourceService eventSourceService) {
|
||||
this.cacheManager = cacheManager;
|
||||
this.threadManger = threadManger;
|
||||
this.deviceGroupService = deviceGroupService;
|
||||
@@ -45,70 +49,104 @@ public class EventSourceCollectService implements ApplicationReadyListener {
|
||||
@Override
|
||||
public void started(ApplicationContext context) {
|
||||
this.eventSourceService.list(Wrappers.<EventSource>lambdaQuery()
|
||||
.eq(EventSource::getStatus, FuncStatus.enabled)).forEach(item -> {
|
||||
|
||||
try {
|
||||
EventSourceDto source = eventSourceService.collectDetailById(item.getId())
|
||||
.ifNotPresentThrow("事件源不存在").getData();
|
||||
|
||||
eventSourceService.listProductById(source.getId(), null).forEach(product -> {
|
||||
if(product.getStatus() == FuncStatus.disabled) {
|
||||
throw new ServiceException("产品[" + product.getName() + "]未启用");
|
||||
}
|
||||
});
|
||||
|
||||
ThreadPoolTaskScheduler scheduler = threadManger.getScheduler();
|
||||
ScheduledFuture<?> schedule = scheduler.schedule(new EventSourceTask(scheduler
|
||||
, source, cacheManager), new CronTrigger(source.getCron()));
|
||||
futures.put(source.getId(), schedule);
|
||||
} catch (ServiceException e) {
|
||||
logger.error("启动事件源失败({}) {}", item.getName(), e.getMessage(), e);
|
||||
eventSourceService.update(Wrappers.<EventSource>lambdaUpdate()
|
||||
.set(EventSource::getReason, e.getMessage())
|
||||
.eq(EventSource::getId, item.getId()));
|
||||
} catch (Exception e) {
|
||||
logger.error("启动事件源失败({}) {}", item.getName(), e.getMessage(), e);
|
||||
eventSourceService.update(Wrappers.<EventSource>lambdaUpdate()
|
||||
.set(EventSource::getReason, "未知错误")
|
||||
.eq(EventSource::getId, item.getId()));
|
||||
}
|
||||
});
|
||||
.eq(EventSource::getStatus, FuncStatus.enabled))
|
||||
.forEach(this::startEventSourceTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动单个事件源任务
|
||||
*/
|
||||
private void startEventSourceTask(EventSource item) {
|
||||
try {
|
||||
EventSourceDto source = eventSourceService.collectDetailById(item.getId())
|
||||
.ifNotPresentThrow("事件源不存在").getData();
|
||||
|
||||
// 校验产品是否启用
|
||||
eventSourceService.listProductById(source.getId(), null).forEach(product -> {
|
||||
if (product.getStatus() == FuncStatus.disabled) {
|
||||
throw new ServiceException("产品[" + product.getName() + "]未启用");
|
||||
}
|
||||
});
|
||||
|
||||
scheduleEventSourceTask(source);
|
||||
|
||||
} catch (ServiceException e) {
|
||||
logger.error("启动事件源失败({}) {}", item.getName(), e.getMessage());
|
||||
eventSourceService.update(Wrappers.<EventSource>lambdaUpdate()
|
||||
.set(EventSource::getReason, e.getMessage())
|
||||
.eq(EventSource::getId, item.getId()));
|
||||
} catch (Exception e) {
|
||||
logger.error("启动事件源失败({}) {}", item.getName(), e.getMessage(), e);
|
||||
eventSourceService.update(Wrappers.<EventSource>lambdaUpdate()
|
||||
.set(EventSource::getReason, "未知错误")
|
||||
.eq(EventSource::getId, item.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调度事件源任务,根据 periodMs 或 cron 选择不同调度方式
|
||||
*/
|
||||
private void scheduleEventSourceTask(EventSourceDto source) {
|
||||
ThreadPoolTaskScheduler scheduler = threadManger.getScheduler();
|
||||
ScheduledFuture<?> scheduledFuture;
|
||||
|
||||
if ("millisecond".equals(source.getPeriodType())) {
|
||||
// 毫秒级采集
|
||||
|
||||
// spring6.0 弃用 scheduleAtFixedRate /scheduleWithFixedDelay 以long 表示时间间隔的方法,改成java.time.Duration
|
||||
if (source.getRateType()==1) {
|
||||
scheduledFuture = scheduler.scheduleAtFixedRate(
|
||||
new EventSourceTask(scheduler, source, cacheManager),
|
||||
Duration.ofMillis(source.getPeriodMs())
|
||||
);
|
||||
} else {
|
||||
scheduledFuture = scheduler.scheduleWithFixedDelay(
|
||||
new EventSourceTask(scheduler, source, cacheManager),
|
||||
Duration.ofMillis(source.getPeriodMs())
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Cron 调度
|
||||
scheduledFuture = scheduler.schedule(
|
||||
new EventSourceTask(scheduler, source, cacheManager),
|
||||
new CronTrigger(source.getCron())
|
||||
);
|
||||
}
|
||||
|
||||
futures.put(source.getId(), scheduledFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态切换事件源任务状态
|
||||
*/
|
||||
public BooleanResult switchTask(Long id, FuncStatus status) {
|
||||
if(status == null) {
|
||||
if (status == null) {
|
||||
return BooleanResult.buildFalse("未指定切换状态");
|
||||
}
|
||||
if(id == null) {
|
||||
if (id == null) {
|
||||
return BooleanResult.buildFalse("未指定事件源id");
|
||||
}
|
||||
|
||||
EventSourceDto source = eventSourceService.collectDetailById(id)
|
||||
.ifNotPresentThrow("事件源不存在").getData();
|
||||
|
||||
if(StrUtil.isBlank(source.getCron())) {
|
||||
return BooleanResult.buildFalse("cron表达式错误");
|
||||
}
|
||||
ScheduledFuture<?> scheduledFuture = futures.get(id);
|
||||
|
||||
ScheduledFuture scheduledFuture = futures.get(id);
|
||||
if(status == FuncStatus.enabled) { // 启用
|
||||
if (status == FuncStatus.enabled) { // 启用
|
||||
this.eventSourceService.listProductById(source.getId(), null).forEach(product -> {
|
||||
if(product.getStatus() == FuncStatus.disabled) {
|
||||
if (product.getStatus() == FuncStatus.disabled) {
|
||||
throw new ServiceException("产品[" + product.getName() + "]未启用");
|
||||
}
|
||||
});
|
||||
|
||||
if(scheduledFuture != null) { // 已经存在则先移除并取消
|
||||
if (scheduledFuture != null) { // 已经存在则先取消
|
||||
futures.remove(id).cancel(true);
|
||||
}
|
||||
|
||||
ThreadPoolTaskScheduler scheduler = threadManger.getScheduler();
|
||||
ScheduledFuture<?> schedule = scheduler.schedule(new EventSourceTask(scheduler
|
||||
, source, cacheManager), new CronTrigger(source.getCron()));
|
||||
futures.put(id, schedule);
|
||||
scheduleEventSourceTask(source);
|
||||
|
||||
} else { // 禁用
|
||||
// 取消定时任务
|
||||
if(scheduledFuture != null) {
|
||||
if (scheduledFuture != null) {
|
||||
futures.remove(id).cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,5 @@ public class EventSourceDto extends EventSource {
|
||||
* 组
|
||||
*/
|
||||
private List<DeviceGroup> groups;
|
||||
|
||||
}
|
||||
|
||||
@@ -38,11 +38,28 @@ public class EventSource extends BaseEntity {
|
||||
*/
|
||||
private EventSourceType type;
|
||||
|
||||
|
||||
/**
|
||||
* 采集类型
|
||||
*/
|
||||
|
||||
private String periodType;
|
||||
|
||||
/**
|
||||
* 采集周期
|
||||
*/
|
||||
private String cron;
|
||||
|
||||
/**
|
||||
* 采集周期 毫秒
|
||||
*/
|
||||
private Long periodMs;
|
||||
|
||||
/**
|
||||
* 控制使用固定速率还是固定延迟 true 固定速率 false 固定延迟
|
||||
*/
|
||||
private int rateType;
|
||||
|
||||
/**
|
||||
* 事件名称
|
||||
*/
|
||||
@@ -97,4 +114,5 @@ public class EventSource extends BaseEntity {
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<String> modelApiIds;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
<result column="id" property="id" />
|
||||
<result column="type" property="type" />
|
||||
<result column="cron" property="cron" />
|
||||
<result column="period_type" property="periodType" />
|
||||
<result column="period_ms" property="periodMs" />
|
||||
<result column="rate_type" property="rateType" />
|
||||
<result column="name" property="name" />
|
||||
<result column="status" property="status" />
|
||||
<result column="has_passive" property="hasPassive" />
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
<result column="id" property="id" />
|
||||
<result column="type" property="type" />
|
||||
<result column="cron" property="cron" />
|
||||
<result column="period_type" property="periodType" />
|
||||
<result column="period_ms" property="periodMs" />
|
||||
<result column="rate_type" property="rateType" />
|
||||
<result column="name" property="name" />
|
||||
<result column="status" property="status" />
|
||||
<result column="has_passive" property="hasPassive" />
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- 添加缺失字段
|
||||
ALTER TABLE iot_event_source
|
||||
ADD COLUMN period_type VARCHAR(20) NOT NULL DEFAULT 'cron' COMMENT '采集类型(cron:定时,millisecond:周期)',
|
||||
ADD COLUMN period_ms BIGINT COMMENT '采集周期毫秒数',
|
||||
ADD COLUMN rate_type TINYINT(1) COMMENT '速率类型(1:固定速率, 0:固定延迟)';
|
||||
Reference in New Issue
Block a user