From f2d80dbaa80a1283bf1c0fe9ae1d280832652d7f Mon Sep 17 00:00:00 2001 From: zhangqian <zhangqian@123.com> Date: 星期四, 02 十一月 2023 18:14:22 +0800 Subject: [PATCH] 增加问题诊断定时任务和查询接口,增加按channel查询工序开始和结束时间 --- api/v1/plc.go | 3 constvar/const.go | 16 ++ api/v1/system.go | 25 +++ service/plc_address/address_map.go | 7 + service/cache_store.go | 55 ++++++- service/problem/check.go | 184 ++++++++++++++++++++++++++ service/system.go | 5 model/response/common.go | 8 crontask/cron_task.go | 6 service/problem/observer.go | 82 +++++++++++ api/v1/task.go | 6 11 files changed, 385 insertions(+), 12 deletions(-) diff --git a/api/v1/plc.go b/api/v1/plc.go index 14750bc..a02e6f8 100644 --- a/api/v1/plc.go +++ b/api/v1/plc.go @@ -46,6 +46,9 @@ } resp.PlcStatus = plcStatus + resp.RealStartTime = service.TaskStartTimeGet(params.Channel) + resp.RealEndTime = service.TaskEndTimeGet(params.Channel) + ctx.OkWithDetailed(resp) } diff --git a/api/v1/system.go b/api/v1/system.go new file mode 100644 index 0000000..5931a9b --- /dev/null +++ b/api/v1/system.go @@ -0,0 +1,25 @@ +package v1 + +import ( + _ "apsClient/model/response" + "apsClient/pkg/contextx" + "apsClient/service/problem" + "github.com/gin-gonic/gin" +) + +type SystemApi struct{} + +// ProblemList +// @Tags 绯荤粺 +// @Summary 闂璇婃柇/闂鍒楄〃 +// @Produce application/json +// @Success 200 {object} contextx.Response{data=[]problem.CheckResult} "鎴愬姛" +// @Router /v1/system/problemList [get] +func (slf *SystemApi) ProblemList(c *gin.Context) { + ctx, ok := contextx.NewContext(c, nil) + if !ok { + return + } + list := problem.Get() + ctx.OkWithDetailed(list) +} diff --git a/api/v1/task.go b/api/v1/task.go index 26cfb2d..0b1c769 100644 --- a/api/v1/task.go +++ b/api/v1/task.go @@ -235,7 +235,7 @@ } service.TaskFlagUnset(procedure.Channel) - + service.TaskEndTimeSet(procedure.Channel, time.Now().Unix()) //璁剧疆宸ュ簭杩愯缁撴潫鏃堕棿 ctx.Ok() } @@ -322,7 +322,9 @@ return } - service.TaskFlagSet(procedure.Channel) + service.TaskFlagSet(procedure.Channel, int(procedure.ID)) + service.TaskStartTimeSet(procedure.Channel, time.Now().Unix()) //璁剧疆宸ュ簭杩愯寮�濮嬫椂闂� + service.TaskEndTimeSet(procedure.Channel, 0) //璁剧疆宸ュ簭杩愯缁撴潫鏃堕棿 ctx.Ok() } diff --git a/constvar/const.go b/constvar/const.go index bb73e7e..3f6fc2b 100644 --- a/constvar/const.go +++ b/constvar/const.go @@ -97,3 +97,19 @@ SerfClusterStatusMaster = "master" //闆嗙兢master SerfClusterStatusSlave = "slave" //闆嗙兢slave ) + +type ProblemCode string + +const ( + ProblemCodeService ProblemCode = "service" //鏈嶅姟涓嶅彲鐢� + ProblemCodeNetwork ProblemCode = "network" //缃戠粶閿欒 + ProblemCodeDB ProblemCode = "db" //鏁版嵁搴撹繛鎺ラ敊璇� + ProblemCodeSerf ProblemCode = "serf" //鏈姞鍏erf闆嗙兢 + ProblemCodeNsq ProblemCode = "nsq" //鏈繛鎺ユ秷鎭槦鍒� + ProblemCodeDevice ProblemCode = "device" //鏈粦瀹氳澶� + ProblemCodeProcessModel ProblemCode = "process_model" //宸ヨ壓鍙傛暟缂哄け + ProblemCodePlcConfig ProblemCode = "plc_config" //plc閰嶇疆缂哄け + ProblemCodePlcAddressList ProblemCode = "plc_address_list" //plc鍦板潃琛ㄧ己澶� + ProblemCodePlcProcessModelAddressList ProblemCode = "plc_process_model_address_list" //plc鍦板潃琛ㄧ己澶� + ProblemCodePlcConnect ProblemCode = "plc_connect" //plc杩炴帴澶辫触 +) diff --git a/crontask/cron_task.go b/crontask/cron_task.go index 66ddf9b..42dc94b 100644 --- a/crontask/cron_task.go +++ b/crontask/cron_task.go @@ -9,6 +9,7 @@ "apsClient/pkg/logx" "apsClient/serf" "apsClient/service" + "apsClient/service/problem" "fmt" "github.com/go-co-op/gocron" "github.com/spf13/cast" @@ -82,6 +83,7 @@ } s.Every(10).Seconds().Do(QueryClusterStatus) //鏌ヨ闆嗙兢鑺傜偣鏁伴噺 + s.Every(30).Seconds().Do(ProblemCheck) //闂璇婃柇 s.StartAsync() return nil @@ -162,3 +164,7 @@ conf.Conf.SerfClusterStatus = clusterStatus conf.Conf.ClusterNodeQuantity = nodeQuantity } + +func ProblemCheck() { + problem.Check() +} diff --git a/model/response/common.go b/model/response/common.go index 9e36958..699292f 100644 --- a/model/response/common.go +++ b/model/response/common.go @@ -54,9 +54,11 @@ } type ProductProgress struct { - FinishNumber int `json:"finishNumber"` - TotalNumber int `json:"totalNumber"` - PlcStatus int `json:"plcStatus"` + FinishNumber int `json:"finishNumber"` + TotalNumber int `json:"totalNumber"` + PlcStatus int `json:"plcStatus"` + RealStartTime int64 `json:"RealStartTime"` + RealEndTime int64 `json:"RealEndTime"` } type TaskCountdown struct { diff --git a/service/cache_store.go b/service/cache_store.go index 1d9b7d1..2ac4594 100644 --- a/service/cache_store.go +++ b/service/cache_store.go @@ -52,6 +52,8 @@ CurrentTaskCacheKey = "current_task:%v" //current_task:channel CurrentProgressCacheKey = "current_progress:%v" //current_progress:channel PlcCacheKeyUpdateTime = "finish_number_update_time:%v" //finish_number_update_time:channel + TaskStartTimeCache = "task_start_time:%v" //task_start_time:channel + TaskEndTimeCache = "task_end_time:%v" //task_end_time:channel ) func PlcCacheGet(channel int32, key string) (interface{}, bool) { @@ -76,28 +78,67 @@ return 0 } +func TaskStartTimeSet(channel int32, ts int64) { + defaultCacheStore.Add(fmt.Sprintf(TaskStartTimeCache, channel), ts) +} + +func TaskStartTimeGet(channel int32) int64 { + if v, ok := defaultCacheStore.Get(fmt.Sprintf(TaskStartTimeCache, channel)); ok { + return v.(int64) + } + procedure, err := model.NewProceduresSearch(nil).SetDeviceId(conf.Conf.CurrentDeviceID).SetStatus(model.ProcedureStatusProcessing).SetChannels([]int32{channel}).First() //杩涜涓换鍔� + if err == gorm.ErrRecordNotFound { + procedure, err = model.NewProceduresSearch(nil).SetDeviceId(conf.Conf.CurrentDeviceID). + SetStatus(model.ProcedureStatusFinished).SetChannels([]int32{channel}).SetOrder("real_end_time desc").First() //涓婁竴涓粨鏉熺殑浠诲姟 + if err == gorm.ErrRecordNotFound { //杩涜涓拰缁撴潫鐨勯兘娌℃湁锛屽紑濮嬫椂闂村拰缁撴潫鏃堕棿閮借缃�0 + TaskStartTimeSet(channel, int64(0)) + TaskEndTimeSet(channel, int64(0)) + return 0 + } else { + TaskStartTimeSet(channel, procedure.RealStartTime) + TaskStartTimeSet(channel, procedure.RealEndTime) + return 0 + } + } else { + TaskStartTimeSet(channel, procedure.RealStartTime) + TaskStartTimeSet(channel, int64(0)) + return procedure.RealStartTime + } +} + +func TaskEndTimeSet(channel int32, ts int64) { + defaultCacheStore.Add(fmt.Sprintf(TaskEndTimeCache, channel), ts) +} + +func TaskEndTimeGet(channel int32) int64 { + if v, ok := defaultCacheStore.Get(fmt.Sprintf(TaskEndTimeCache, channel)); ok { + return v.(int64) + } + return 0 +} + func FinishUpdateTimeSet(channel int32, value interface{}) { defaultCacheStore.Add(fmt.Sprintf(PlcCacheKeyUpdateTime, channel), value) } -func TaskFlagSet(channel int32) { - defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), true) +func TaskFlagSet(channel int32, taskId int) { + defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), taskId) } func TaskFlagUnset(channel int32) { - defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), false) + defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), 0) } func TaskFlagGet(channel int32) bool { if v, ok := defaultCacheStore.Get(fmt.Sprintf(CurrentTaskCacheKey, channel)); ok { - return v.(bool) + return v.(int) > 0 } - _, err := model.NewProceduresSearch(nil).SetDeviceId(conf.Conf.CurrentDeviceID).SetStatus(model.ProcedureStatusProcessing).SetChannels([]int32{channel}).First() + procedure, err := model.NewProceduresSearch(nil).SetDeviceId(conf.Conf.CurrentDeviceID).SetStatus(model.ProcedureStatusProcessing).SetChannels([]int32{channel}).First() if err == gorm.ErrRecordNotFound { - defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), false) + defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), 0) return false } else { - defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), true) + defaultCacheStore.Add(fmt.Sprintf(CurrentTaskCacheKey, channel), int(procedure.ID)) return true } } diff --git a/service/plc_address/address_map.go b/service/plc_address/address_map.go index 609bf22..0bf753b 100644 --- a/service/plc_address/address_map.go +++ b/service/plc_address/address_map.go @@ -36,6 +36,12 @@ return 0, false } +var LoadOk bool + +func IsLoad() bool { + return LoadOk +} + func LoadAddressFromFile() (loadOk bool) { keyFileName := fmt.Sprintf("%s%s", constvar.PlcAddressDataPath, constvar.PlcAddressDataKeyFileName) addressFileName := fmt.Sprintf("%s%s", constvar.PlcAddressDataPath, constvar.PlcAddressDataValueFileName) @@ -65,5 +71,6 @@ address := cast.ToInt(strings.ReplaceAll(addresses[i], "\r", "")) Set(key, address) } + LoadOk = true return true } diff --git a/service/problem/check.go b/service/problem/check.go new file mode 100644 index 0000000..a7110d6 --- /dev/null +++ b/service/problem/check.go @@ -0,0 +1,184 @@ +package problem + +import ( + "apsClient/conf" + "apsClient/constvar" + "apsClient/pkg/sqlitex" + "apsClient/service" + "apsClient/service/plc_address" + "sync" +) + +var checkItems = []constvar.ProblemCode{ + constvar.ProblemCodeService, + constvar.ProblemCodeNetwork, + constvar.ProblemCodeDB, + constvar.ProblemCodeSerf, + constvar.ProblemCodeNsq, + constvar.ProblemCodeDevice, + constvar.ProblemCodeProcessModel, + constvar.ProblemCodePlcConfig, + constvar.ProblemCodePlcAddressList, + constvar.ProblemCodePlcProcessModelAddressList, + constvar.ProblemCodePlcConnect, +} +var itemNameMap = map[constvar.ProblemCode]string{ + constvar.ProblemCodeService: "鏈嶅姟", + constvar.ProblemCodeNetwork: "缃戠粶杩炴帴", + constvar.ProblemCodeDB: "鏁版嵁搴�", + constvar.ProblemCodeSerf: "serf闆嗙兢", + constvar.ProblemCodeNsq: "娑堟伅闃熷垪", + constvar.ProblemCodeDevice: "鐢熶骇璁惧缁戝畾", + constvar.ProblemCodeProcessModel: "宸ヨ壓鍙傛暟", + constvar.ProblemCodePlcConfig: "plc閰嶇疆", + constvar.ProblemCodePlcAddressList: "plc鍦板潃琛�", + constvar.ProblemCodePlcProcessModelAddressList: "plc宸ヨ壓鍙傛暟鍦板潃琛�", + constvar.ProblemCodePlcConnect: "plc杩炴帴", +} + +type CheckResult struct { + ItemCode constvar.ProblemCode + ItemName string + CheckResult bool +} + +var checkResultList []*CheckResult +var mutex sync.RWMutex + +func Check() { + checkResultListTemp := make([]*CheckResult, 0) + var checkObj check + for _, item := range checkItems { + switch item { + case constvar.ProblemCodeService: + checkObj = &Default{} + case constvar.ProblemCodeNetwork: + checkObj = &Network{} + case constvar.ProblemCodeDB: + checkObj = &DB{} + case constvar.ProblemCodeSerf: + checkObj = &Serf{} + case constvar.ProblemCodeNsq: + checkObj = &Nsq{} + case constvar.ProblemCodeDevice: + checkObj = &Device{} + case constvar.ProblemCodePlcConfig: + checkObj = &PlcConfig{} + case constvar.ProblemCodePlcAddressList: + checkObj = &PlcAddressList{} + case constvar.ProblemCodePlcProcessModelAddressList: + checkObj = &PlcProcessModelAddressList{} + case constvar.ProblemCodePlcConnect: + checkObj = &PlcConnect{} + } + checkResultList = append(checkResultList, &CheckResult{ + ItemCode: item, + ItemName: itemNameMap[item], + CheckResult: checkObj.Check(), + }) + } + mutex.Lock() + checkResultList = checkResultListTemp + mutex.Unlock() +} + +func Get() []*CheckResult { + mutex.RLock() + defer mutex.RUnlock() + return checkResultList + +} + +type check interface { + Check() bool +} + +type Default struct{} + +func (slf *Default) Check() bool { + return true +} + +type Network struct{} + +func (slf *Network) Check() bool { + return false +} + +type DB struct{} + +func (slf *DB) Check() bool { + err := sqlitex.GetDB().DB().Ping() + if err != nil { + return false + } + return true +} + +type Serf struct{} + +func (slf *Serf) Check() bool { + return conf.Conf.SerfClusterStatus != "" +} + +type Nsq struct{} + +func (slf *Nsq) Check() bool { + return false +} + +type Device struct{} + +func (slf *Device) Check() bool { + list, err := service.GetDeviceIDList() + if err != nil { + return false + } + return len(list) > 0 +} + +type ProcessModel struct { +} + +func (slf *ProcessModel) Check() bool { + return false +} + +type PlcConfig struct{} + +func (slf *PlcConfig) Check() bool { + plcConfig, _ := service.NewDevicePlcService().GetDevicePlc() + if plcConfig.Method == "" { + return false + } + if plcConfig.Method == constvar.PlcMethodModbusTCP && (plcConfig.Address == "" || plcConfig.Port == 0) { + return false + } + if plcConfig.Method == constvar.PlcMethodSerial && (plcConfig.BaudRate == 0 || plcConfig.SerialName == "") { + return false + } + + if plcConfig.Method == constvar.PlcMethodModbusRTU && (plcConfig.DataBit == 0 || plcConfig.StopBit == 0 || plcConfig.Parity == 0) { + return false + } + return true +} + +type PlcAddressList struct{} + +func (slf *PlcAddressList) Check() bool { + plcConfig, _ := service.NewDevicePlcService().GetDevicePlc() + return len(plcConfig.Details) > 0 +} + +type PlcProcessModelAddressList struct{} + +func (slf *PlcProcessModelAddressList) Check() bool { + return plc_address.IsLoad() +} + +type PlcConnect struct{} + +func (slf *PlcConnect) Check() bool { + return service.PlcIsConnect() +} diff --git a/service/problem/observer.go b/service/problem/observer.go new file mode 100644 index 0000000..7a3638a --- /dev/null +++ b/service/problem/observer.go @@ -0,0 +1,82 @@ +package problem + +import "fmt" + +// Subject 涓婚鎺ュ彛 +type Subject interface { + Register(observer Observer) + Deregister(observer Observer) + Notify(data interface{}) +} + +// Observer 瑙傚療鑰呮帴鍙� +type Observer interface { + Update(data interface{}) +} + +// BaseSubject 涓婚鍩虹被瀹炵幇 +type BaseSubject struct { + observers []Observer +} + +func (s *BaseSubject) Register(observer Observer) { + s.observers = append(s.observers, observer) +} + +func (s *BaseSubject) Deregister(observer Observer) { + for i, obs := range s.observers { + if obs == observer { + s.observers = append(s.observers[:i], s.observers[i+1:]...) + return + } + } +} + +func (s *BaseSubject) Notify(data interface{}) { + for _, obs := range s.observers { + obs.Update(data) + } +} + +//// 涓婚瀹炵幇 +//type ConcreteSubject struct { +// BaseSubject +//} +// +//// 瑙傚療鑰呭疄鐜� +//type ConcreteObserver struct { +// name string +//} +// +//func (o *ConcreteObserver) Update(data interface{}) { +// fmt.Printf("%s 鏀跺埌閫氱煡锛�%v\n", o.name, data) +//} +// +//func main() { +// subject := &ConcreteSubject{} +// +// observer1 := &ConcreteObserver{name: "瑙傚療鑰�1"} +// observer2 := &ConcreteObserver{name: "瑙傚療鑰�2"} +// +// subject.Register(observer1) +// subject.Register(observer2) +// +// subject.Notify("鏂版暟鎹�1") +// subject.Deregister(observer1) +// +// subject.Notify("鏂版暟鎹�2") +//} + +// 涓婚瀹炵幇 +type EventSubject struct { + BaseSubject +} + +// 瑙傚療鑰呭疄鐜� +type EventObserver struct { + name string +} + +func (o *EventObserver) Update(data interface{}) { + fmt.Printf("%s 鏀跺埌閫氱煡锛�%v\n", o.name, data) +} diff --git a/service/system.go b/service/system.go new file mode 100644 index 0000000..bde2c9e --- /dev/null +++ b/service/system.go @@ -0,0 +1,5 @@ +package service + +func GetProblemList() { + +} -- Gitblit v1.8.0