fix: 修复客户端实例记录问题并删除父应用功能
- 客户端实例唯一标识改为 app_config_id+appName+env+ip 四元组 - 新增 last_ping_at 字段,轮询即更新,拉取配置时更新 last_fetch_at - FetchChangedConfigs 无变更时也记录客户端实例 - 清理逻辑改为基于 last_ping_at 超过5分钟删除 - 删除父应用(ParentId)相关功能
This commit is contained in:
@@ -103,7 +103,6 @@ func (h *AppHandler) GetById(c *gin.Context) {
|
|||||||
type AddAppRequest struct {
|
type AddAppRequest struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
GroupId *int `json:"groupId"`
|
GroupId *int `json:"groupId"`
|
||||||
ParentId *int `json:"parentId"`
|
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
Code string `json:"code" binding:"required"`
|
Code string `json:"code" binding:"required"`
|
||||||
ServiceId string `json:"serviceId"`
|
ServiceId string `json:"serviceId"`
|
||||||
@@ -141,7 +140,6 @@ func (h *AppHandler) Add(c *gin.Context) {
|
|||||||
|
|
||||||
app := model.Application{
|
app := model.Application{
|
||||||
GroupId: req.GroupId,
|
GroupId: req.GroupId,
|
||||||
ParentId: req.ParentId,
|
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Code: req.Code,
|
Code: req.Code,
|
||||||
ServiceId: req.ServiceId,
|
ServiceId: req.ServiceId,
|
||||||
@@ -153,15 +151,6 @@ func (h *AppHandler) Add(c *gin.Context) {
|
|||||||
CreatedBy: userInfo.Name,
|
CreatedBy: userInfo.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ParentId != nil {
|
|
||||||
var parent model.Application
|
|
||||||
if has, _ := dao.Engine.ID(*req.ParentId).Get(&parent); has {
|
|
||||||
app.GroupId = parent.GroupId
|
|
||||||
app.IsModule = true
|
|
||||||
app.Code = parent.Code + "-" + req.Code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dao.Engine.Insert(&app)
|
dao.Engine.Insert(&app)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func (h *ConfigHandler) List(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
var results []countResult
|
var results []countResult
|
||||||
dao.Engine.Table("client_instance").
|
dao.Engine.Table("client_instance").
|
||||||
Select("app_config_id, COUNT(DISTINCT ip) as cnt").
|
Select("app_config_id, COUNT(*) as cnt").
|
||||||
In("app_config_id", configIds).
|
In("app_config_id", configIds).
|
||||||
GroupBy("app_config_id").
|
GroupBy("app_config_id").
|
||||||
Find(&results)
|
Find(&results)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ConfigApiHandler struct {
|
type ConfigApiHandler struct {
|
||||||
parseService *service.ConfigParseService
|
parseService *service.ConfigParseService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfigApiHandler(parse *service.ConfigParseService) *ConfigApiHandler {
|
func NewConfigApiHandler(parse *service.ConfigParseService) *ConfigApiHandler {
|
||||||
@@ -86,20 +86,6 @@ func (h *ConfigApiHandler) FetchAllConfigs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load parent app configs
|
|
||||||
if app.ParentId != nil {
|
|
||||||
var parentConfigs []model.AppConfig
|
|
||||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ?",
|
|
||||||
req.Env, version, *app.ParentId).Find(&parentConfigs)
|
|
||||||
for _, cfg := range parentConfigs {
|
|
||||||
configIds = append(configIds, cfg.Id)
|
|
||||||
kvMap := h.parseService.ParseConfigToKVMap(&cfg)
|
|
||||||
for k, v := range kvMap {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load app configs
|
// load app configs
|
||||||
var appConfigs []model.AppConfig
|
var appConfigs []model.AppConfig
|
||||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ?",
|
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ?",
|
||||||
@@ -176,30 +162,41 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load parent app changed configs
|
|
||||||
if app.ParentId != nil {
|
|
||||||
var parentConfigs []model.AppConfig
|
|
||||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ? AND updated_at > ?",
|
|
||||||
req.Env, version, *app.ParentId, lastUpdateTime).Find(&parentConfigs)
|
|
||||||
for _, cfg := range parentConfigs {
|
|
||||||
configIds = append(configIds, cfg.Id)
|
|
||||||
h.addChangedConfigs(result, &cfg, req.FetchAll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load app changed configs
|
// load app changed configs
|
||||||
var appConfigs []model.AppConfig
|
var appConfigs1 []model.AppConfig
|
||||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ? AND updated_at > ?",
|
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ? AND updated_at > ?",
|
||||||
req.Env, version, app.Id, lastUpdateTime).Find(&appConfigs)
|
req.Env, version, app.Id, lastUpdateTime).Find(&appConfigs1)
|
||||||
for _, cfg := range appConfigs {
|
for _, cfg := range appConfigs1 {
|
||||||
configIds = append(configIds, cfg.Id)
|
configIds = append(configIds, cfg.Id)
|
||||||
h.addChangedConfigs(result, &cfg, req.FetchAll)
|
h.addChangedConfigs(result, &cfg, req.FetchAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
result["latest.fetch.timestamp"] = strconv.FormatInt(time.Now().UnixMilli(), 10)
|
result["latest.fetch.timestamp"] = strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
|
||||||
|
// query all config ids for this app to record client instances
|
||||||
|
var allConfigIds []int
|
||||||
|
if !req.IgnoreGlobal && app.GroupId != nil {
|
||||||
|
var globalConfigs []model.AppConfig
|
||||||
|
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND group_id = ? AND (app_id is null OR app_id = 0)",
|
||||||
|
req.Env, version, *app.GroupId).Find(&globalConfigs)
|
||||||
|
for _, cfg := range globalConfigs {
|
||||||
|
allConfigIds = append(allConfigIds, cfg.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var appConfigs2 []model.AppConfig
|
||||||
|
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ?",
|
||||||
|
req.Env, version, app.Id).Find(&appConfigs2)
|
||||||
|
for _, cfg := range appConfigs2 {
|
||||||
|
allConfigIds = append(allConfigIds, cfg.Id)
|
||||||
|
}
|
||||||
|
|
||||||
// record client instances asynchronously
|
// record client instances asynchronously
|
||||||
go h.recordClientInstances(c.ClientIP(), configIds, req.AppName, req.Env, "fetchChanged")
|
// only update last_fetch_at if there are actual changes
|
||||||
|
fetchType := ""
|
||||||
|
if len(configIds) > 0 {
|
||||||
|
fetchType = "fetchChanged"
|
||||||
|
}
|
||||||
|
go h.recordClientInstances(c.ClientIP(), allConfigIds, req.AppName, req.Env, fetchType)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: result})
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: result})
|
||||||
}
|
}
|
||||||
@@ -218,29 +215,41 @@ func (h *ConfigApiHandler) recordClientInstances(ip string, configIds []int, app
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
for _, configId := range configIds {
|
for _, configId := range configIds {
|
||||||
var existing model.ClientInstance
|
var existing model.ClientInstance
|
||||||
has, _ := dao.Engine.Where("app_config_id = ? AND ip = ?", configId, ip).Get(&existing)
|
has, _ := dao.Engine.Where("app_config_id = ? AND app_name = ? AND env = ? AND ip = ?", configId, appName, env, ip).Get(&existing)
|
||||||
if has {
|
if has {
|
||||||
existing.LastFetchAt = &now
|
existing.LastPingAt = &now
|
||||||
existing.LastFetchType = fetchType
|
|
||||||
existing.UpdatedAt = &now
|
existing.UpdatedAt = &now
|
||||||
dao.Engine.ID(existing.Id).Cols("last_fetch_at", "last_fetch_type", "updated_at").Update(&existing)
|
if fetchType != "" {
|
||||||
|
existing.LastFetchAt = &now
|
||||||
|
existing.LastFetchType = fetchType
|
||||||
|
dao.Engine.ID(existing.Id).Cols("last_ping_at", "last_fetch_at", "last_fetch_type", "updated_at").Update(&existing)
|
||||||
|
} else {
|
||||||
|
dao.Engine.ID(existing.Id).Cols("last_ping_at", "updated_at").Update(&existing)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
instance := model.ClientInstance{
|
instance := model.ClientInstance{
|
||||||
AppConfigId: configId,
|
AppConfigId: configId,
|
||||||
AppName: appName,
|
AppName: appName,
|
||||||
Env: env,
|
Env: env,
|
||||||
IP: ip,
|
Ip: ip,
|
||||||
LastFetchAt: &now,
|
LastPingAt: &now,
|
||||||
LastFetchType: fetchType,
|
|
||||||
CreatedAt: &now,
|
CreatedAt: &now,
|
||||||
UpdatedAt: &now,
|
UpdatedAt: &now,
|
||||||
}
|
}
|
||||||
dao.Engine.Insert(&instance)
|
if fetchType != "" {
|
||||||
|
instance.LastFetchAt = &now
|
||||||
|
instance.LastFetchType = fetchType
|
||||||
|
}
|
||||||
|
_, err := dao.Engine.Insert(&instance)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[recordClientInstances] insert error: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cleanup records older than 5 minutes
|
// cleanup records older than 5 minutes
|
||||||
fiveMinutesAgo := now.Add(-5 * time.Minute)
|
fiveMinutesAgo := now.Add(-5 * time.Minute)
|
||||||
dao.Engine.Where("last_fetch_at < ?", fiveMinutesAgo).Delete(&model.ClientInstance{})
|
dao.Engine.Where("last_ping_at < ?", fiveMinutesAgo).Delete(&model.ClientInstance{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (h *ConfigApiHandler) Ping(c *gin.Context) {
|
// func (h *ConfigApiHandler) Ping(c *gin.Context) {
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ import "time"
|
|||||||
type Application struct {
|
type Application struct {
|
||||||
Id int `xorm:"int autoincr pk" json:"id"`
|
Id int `xorm:"int autoincr pk" json:"id"`
|
||||||
GroupId *int `xorm:"int" json:"groupId"`
|
GroupId *int `xorm:"int" json:"groupId"`
|
||||||
ParentId *int `xorm:"int" json:"parentId"`
|
|
||||||
Name string `xorm:"varchar(32)" json:"name"`
|
Name string `xorm:"varchar(32)" json:"name"`
|
||||||
Code string `xorm:"varchar(32)" json:"code"`
|
Code string `xorm:"varchar(32)" json:"code"`
|
||||||
ServiceId string `xorm:"varchar(64)" json:"serviceId"`
|
ServiceId string `xorm:"varchar(64)" json:"serviceId"`
|
||||||
Token string `xorm:"varchar(64)" json:"token"`
|
Token string `xorm:"varchar(64)" json:"token"`
|
||||||
IsModule bool `xorm:"tinyint(1) default 1" json:"isModule"`
|
|
||||||
OwnerId *int `xorm:"int" json:"ownerId"`
|
OwnerId *int `xorm:"int" json:"ownerId"`
|
||||||
OwnerName string `xorm:"varchar(16)" json:"ownerName"`
|
OwnerName string `xorm:"varchar(16)" json:"ownerName"`
|
||||||
Remarks string `xorm:"text" json:"remarks"`
|
Remarks string `xorm:"text" json:"remarks"`
|
||||||
@@ -19,7 +17,5 @@ type Application struct {
|
|||||||
CreatedBy string `xorm:"varchar(32)" json:"createdBy"`
|
CreatedBy string `xorm:"varchar(32)" json:"createdBy"`
|
||||||
UpdatedAt *time.Time `xorm:"datetime" json:"updatedAt"`
|
UpdatedAt *time.Time `xorm:"datetime" json:"updatedAt"`
|
||||||
UpdatedBy string `xorm:"varchar(32)" json:"updatedBy"`
|
UpdatedBy string `xorm:"varchar(32)" json:"updatedBy"`
|
||||||
ParentName string `xorm:"-" json:"parentName,omitempty"`
|
|
||||||
FullName string `xorm:"-" json:"fullName,omitempty"`
|
|
||||||
GroupName string `xorm:"-" json:"groupName,omitempty"`
|
GroupName string `xorm:"-" json:"groupName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import "time"
|
|||||||
|
|
||||||
type ClientInstance struct {
|
type ClientInstance struct {
|
||||||
Id int `xorm:"int autoincr pk" json:"id"`
|
Id int `xorm:"int autoincr pk" json:"id"`
|
||||||
AppConfigId int `xorm:"int index" json:"appConfigId"`
|
AppConfigId int `xorm:"int unique(udx_aaei)" json:"appConfigId"`
|
||||||
AppName string `xorm:"varchar(64) index" json:"appName"`
|
AppName string `xorm:"varchar(64) unique(udx_aaei)" json:"appName"`
|
||||||
Env string `xorm:"varchar(32)" json:"env"`
|
Env string `xorm:"varchar(32) unique(udx_aaei)" json:"env"`
|
||||||
IP string `xorm:"varchar(64)" json:"ip"`
|
Ip string `xorm:"varchar(64) unique(udx_aaei)" json:"ip"`
|
||||||
|
LastPingAt *time.Time `xorm:"datetime" json:"lastPingAt"`
|
||||||
LastFetchAt *time.Time `xorm:"datetime" json:"lastFetchAt"`
|
LastFetchAt *time.Time `xorm:"datetime" json:"lastFetchAt"`
|
||||||
LastFetchType string `xorm:"varchar(16)" json:"lastFetchType"`
|
LastFetchType string `xorm:"varchar(16)" json:"lastFetchType"`
|
||||||
CreatedAt *time.Time `xorm:"datetime" json:"createdAt"`
|
CreatedAt *time.Time `xorm:"datetime" json:"createdAt"`
|
||||||
|
|||||||
Reference in New Issue
Block a user