实现定时采集
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/collection"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
||||
domain_notify "git.huangwc.com/pig/pig-farm-controller/internal/domain/notify"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/pig"
|
||||
@@ -28,11 +29,12 @@ import (
|
||||
|
||||
// Application 是整个应用的核心,封装了所有组件和生命周期。
|
||||
type Application struct {
|
||||
Config *config.Config
|
||||
Logger *logs.Logger
|
||||
Storage database.Storage
|
||||
Executor *task.Scheduler
|
||||
API *api.API // 添加 API 对象
|
||||
Config *config.Config
|
||||
Logger *logs.Logger
|
||||
Storage database.Storage
|
||||
Executor *task.Scheduler
|
||||
API *api.API
|
||||
Collector collection.Collector
|
||||
|
||||
// 新增的仓库和管理器字段,以便在 initializePendingTasks 中访问
|
||||
planRepo repository.PlanRepository
|
||||
@@ -177,6 +179,14 @@ func NewApplication(configPath string) (*Application, error) {
|
||||
cfg.Task.NumWorkers,
|
||||
)
|
||||
|
||||
// --- 初始化定时采集器 ---
|
||||
timedCollector := collection.NewTimedCollector(
|
||||
deviceRepo,
|
||||
generalDeviceService,
|
||||
logger,
|
||||
time.Duration(cfg.Collection.Interval)*time.Second,
|
||||
)
|
||||
|
||||
// 初始化 API 服务器
|
||||
apiServer := api.NewAPI(
|
||||
cfg.Server,
|
||||
@@ -204,6 +214,7 @@ func NewApplication(configPath string) (*Application, error) {
|
||||
Storage: storage,
|
||||
Executor: executor,
|
||||
API: apiServer,
|
||||
Collector: timedCollector,
|
||||
planRepo: planRepo,
|
||||
pendingTaskRepo: pendingTaskRepo,
|
||||
executionLogRepo: executionLogRepo,
|
||||
@@ -327,6 +338,9 @@ func (app *Application) Start() error {
|
||||
// 启动任务执行器
|
||||
app.Executor.Start()
|
||||
|
||||
// 启动定时采集器
|
||||
app.Collector.Start()
|
||||
|
||||
// 启动 API 服务器
|
||||
app.API.Start()
|
||||
|
||||
@@ -349,6 +363,9 @@ func (app *Application) Stop() error {
|
||||
// 关闭任务执行器
|
||||
app.Executor.Stop()
|
||||
|
||||
// 关闭定时采集器
|
||||
app.Collector.Stop()
|
||||
|
||||
// 断开数据库连接
|
||||
if err := app.Storage.Disconnect(); err != nil {
|
||||
app.Logger.Errorw("数据库连接断开失败", "error", err)
|
||||
|
||||
6
internal/domain/collection/collector.go
Normal file
6
internal/domain/collection/collector.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package collection
|
||||
|
||||
type Collector interface {
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
89
internal/domain/collection/timed_collector.go
Normal file
89
internal/domain/collection/timed_collector.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package collection
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||
)
|
||||
|
||||
// TimedCollector 实现了 Collector 接口,用于定时从数据库获取设备信息并下发采集指令
|
||||
type TimedCollector struct {
|
||||
deviceRepo repository.DeviceRepository
|
||||
deviceService device.Service
|
||||
logger *logs.Logger
|
||||
interval time.Duration
|
||||
ticker *time.Ticker
|
||||
done chan bool
|
||||
}
|
||||
|
||||
// NewTimedCollector 创建一个定时采集器实例
|
||||
func NewTimedCollector(
|
||||
deviceRepo repository.DeviceRepository,
|
||||
deviceService device.Service,
|
||||
logger *logs.Logger,
|
||||
interval time.Duration,
|
||||
) Collector {
|
||||
return &TimedCollector{
|
||||
deviceRepo: deviceRepo,
|
||||
deviceService: deviceService,
|
||||
logger: logger,
|
||||
interval: interval,
|
||||
done: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开始定时采集
|
||||
func (c *TimedCollector) Start() {
|
||||
c.logger.Infof("定时采集器启动,采集间隔: %s", c.interval)
|
||||
c.ticker = time.NewTicker(c.interval)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-c.done:
|
||||
return
|
||||
case <-c.ticker.C:
|
||||
c.collect()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop 停止定时采集
|
||||
func (c *TimedCollector) Stop() {
|
||||
c.logger.Info("定时采集器停止")
|
||||
c.ticker.Stop()
|
||||
c.done <- true
|
||||
}
|
||||
|
||||
// collect 是核心的采集逻辑
|
||||
func (c *TimedCollector) collect() {
|
||||
c.logger.Info("开始新一轮的设备数据采集")
|
||||
|
||||
sensors, err := c.deviceRepo.ListAllSensors()
|
||||
if err != nil {
|
||||
c.logger.Errorf("采集周期: 从数据库获取所有传感器失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(sensors) == 0 {
|
||||
c.logger.Info("采集周期: 未发现任何传感器设备,跳过本次采集")
|
||||
return
|
||||
}
|
||||
|
||||
sensorsByController := make(map[uint][]*models.Device)
|
||||
for _, sensor := range sensors {
|
||||
sensorsByController[sensor.AreaControllerID] = append(sensorsByController[sensor.AreaControllerID], sensor)
|
||||
}
|
||||
|
||||
for controllerID, controllerSensors := range sensorsByController {
|
||||
c.logger.Infof("采集周期: 准备为区域主控 %d 下的 %d 个传感器下发采集指令", controllerID, len(controllerSensors))
|
||||
if err := c.deviceService.Collect(controllerID, controllerSensors); err != nil {
|
||||
c.logger.Errorf("采集周期: 为区域主控 %d 下发采集指令失败: %v", controllerID, err)
|
||||
}
|
||||
}
|
||||
|
||||
c.logger.Info("本轮设备数据采集完成")
|
||||
}
|
||||
@@ -44,6 +44,9 @@ type Config struct {
|
||||
|
||||
// Notify 通知服务配置
|
||||
Notify NotifyConfig `yaml:"notify"`
|
||||
|
||||
// Collection 定时采集配置
|
||||
Collection CollectionConfig `yaml:"collection"`
|
||||
}
|
||||
|
||||
// AppConfig 代表应用基础配置
|
||||
@@ -195,6 +198,11 @@ type LarkConfig struct {
|
||||
AppSecret string `yaml:"appSecret"`
|
||||
}
|
||||
|
||||
// CollectionConfig 代表定时采集配置
|
||||
type CollectionConfig struct {
|
||||
Interval int `yaml:"interval"`
|
||||
}
|
||||
|
||||
// NewConfig 创建并返回一个新的配置实例
|
||||
func NewConfig() *Config {
|
||||
// 默认值可以在这里设置,但我们优先使用配置文件中的值
|
||||
|
||||
@@ -23,6 +23,9 @@ type DeviceRepository interface {
|
||||
// ListAll 获取所有设备的列表
|
||||
ListAll() ([]*models.Device, error)
|
||||
|
||||
// ListAllSensors 获取所有传感器类型的设备列表
|
||||
ListAllSensors() ([]*models.Device, error)
|
||||
|
||||
// ListByAreaControllerID 根据区域主控 ID 列出所有子设备。
|
||||
ListByAreaControllerID(areaControllerID uint) ([]*models.Device, error)
|
||||
|
||||
@@ -84,6 +87,19 @@ func (r *gormDeviceRepository) ListAll() ([]*models.Device, error) {
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
// ListAllSensors 检索归类为传感器的所有设备
|
||||
func (r *gormDeviceRepository) ListAllSensors() ([]*models.Device, error) {
|
||||
var sensors []*models.Device
|
||||
err := r.db.Preload("AreaController").Preload("DeviceTemplate").
|
||||
Joins("JOIN device_templates ON device_templates.id = devices.device_template_id").
|
||||
Where("device_templates.category = ?", models.CategorySensor).
|
||||
Find(&sensors).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询所有传感器失败: %w", err)
|
||||
}
|
||||
return sensors, nil
|
||||
}
|
||||
|
||||
// ListByAreaControllerID 根据区域主控 ID 列出所有子设备
|
||||
func (r *gormDeviceRepository) ListByAreaControllerID(areaControllerID uint) ([]*models.Device, error) {
|
||||
var devices []*models.Device
|
||||
|
||||
Reference in New Issue
Block a user