feat: add panic recovery and retry mechanism for InitChannelCache; improve batch deletion of abilities in FixAbility
This commit is contained in:
19
main.go
19
main.go
@@ -89,9 +89,22 @@ func main() {
|
|||||||
if common.MemoryCacheEnabled {
|
if common.MemoryCacheEnabled {
|
||||||
common.SysLog("memory cache enabled")
|
common.SysLog("memory cache enabled")
|
||||||
common.SysError(fmt.Sprintf("sync frequency: %d seconds", common.SyncFrequency))
|
common.SysError(fmt.Sprintf("sync frequency: %d seconds", common.SyncFrequency))
|
||||||
model.InitChannelCache()
|
|
||||||
}
|
// Add panic recovery and retry for InitChannelCache
|
||||||
if common.MemoryCacheEnabled {
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
common.SysError(fmt.Sprintf("InitChannelCache panic: %v, retrying once", r))
|
||||||
|
// Retry once
|
||||||
|
_, fixErr := model.FixAbility()
|
||||||
|
if fixErr != nil {
|
||||||
|
common.SysError(fmt.Sprintf("InitChannelCache failed: %s", fixErr.Error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
model.InitChannelCache()
|
||||||
|
}()
|
||||||
|
|
||||||
go model.SyncOptions(common.SyncFrequency)
|
go model.SyncOptions(common.SyncFrequency)
|
||||||
go model.SyncChannelCache(common.SyncFrequency)
|
go model.SyncChannelCache(common.SyncFrequency)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func getPriority(group string, model string, retry int) (int, error) {
|
|||||||
err := DB.Model(&Ability{}).
|
err := DB.Model(&Ability{}).
|
||||||
Select("DISTINCT(priority)").
|
Select("DISTINCT(priority)").
|
||||||
Where(groupCol+" = ? and model = ? and enabled = "+trueVal, group, model).
|
Where(groupCol+" = ? and model = ? and enabled = "+trueVal, group, model).
|
||||||
Order("priority DESC"). // 按优先级降序排序
|
Order("priority DESC"). // 按优先级降序排序
|
||||||
Pluck("priority", &priorities).Error // Pluck用于将查询的结果直接扫描到一个切片中
|
Pluck("priority", &priorities).Error // Pluck用于将查询的结果直接扫描到一个切片中
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -261,12 +261,28 @@ func FixAbility() (int, error) {
|
|||||||
common.SysError(fmt.Sprintf("Get channel ids from channel table failed: %s", err.Error()))
|
common.SysError(fmt.Sprintf("Get channel ids from channel table failed: %s", err.Error()))
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
// Delete abilities of channels that are not in channel table
|
|
||||||
err = DB.Where("channel_id NOT IN (?)", channelIds).Delete(&Ability{}).Error
|
// Delete abilities of channels that are not in channel table - in batches to avoid too many placeholders
|
||||||
if err != nil {
|
if len(channelIds) > 0 {
|
||||||
common.SysError(fmt.Sprintf("Delete abilities of channels that are not in channel table failed: %s", err.Error()))
|
// Process deletion in chunks to avoid "too many placeholders" error
|
||||||
return 0, err
|
for _, chunk := range lo.Chunk(channelIds, 100) {
|
||||||
|
err = DB.Where("channel_id NOT IN (?)", chunk).Delete(&Ability{}).Error
|
||||||
|
if err != nil {
|
||||||
|
common.SysError(fmt.Sprintf("Delete abilities of channels (batch) that are not in channel table failed: %s", err.Error()))
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If no channels exist, delete all abilities
|
||||||
|
err = DB.Delete(&Ability{}).Error
|
||||||
|
if err != nil {
|
||||||
|
common.SysError(fmt.Sprintf("Delete all abilities failed: %s", err.Error()))
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
common.SysLog("Delete all abilities successfully")
|
||||||
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
common.SysLog(fmt.Sprintf("Delete abilities of channels that are not in channel table successfully, ids: %v", channelIds))
|
common.SysLog(fmt.Sprintf("Delete abilities of channels that are not in channel table successfully, ids: %v", channelIds))
|
||||||
count += len(channelIds)
|
count += len(channelIds)
|
||||||
|
|
||||||
@@ -275,17 +291,26 @@ func FixAbility() (int, error) {
|
|||||||
err = DB.Table("abilities").Distinct("channel_id").Pluck("channel_id", &abilityChannelIds).Error
|
err = DB.Table("abilities").Distinct("channel_id").Pluck("channel_id", &abilityChannelIds).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysError(fmt.Sprintf("Get channel ids from abilities table failed: %s", err.Error()))
|
common.SysError(fmt.Sprintf("Get channel ids from abilities table failed: %s", err.Error()))
|
||||||
return 0, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var channels []Channel
|
var channels []Channel
|
||||||
if len(abilityChannelIds) == 0 {
|
if len(abilityChannelIds) == 0 {
|
||||||
err = DB.Find(&channels).Error
|
err = DB.Find(&channels).Error
|
||||||
} else {
|
} else {
|
||||||
err = DB.Where("id NOT IN (?)", abilityChannelIds).Find(&channels).Error
|
// Process query in chunks to avoid "too many placeholders" error
|
||||||
}
|
err = nil
|
||||||
if err != nil {
|
for _, chunk := range lo.Chunk(abilityChannelIds, 100) {
|
||||||
return 0, err
|
var channelsChunk []Channel
|
||||||
|
err = DB.Where("id NOT IN (?)", chunk).Find(&channelsChunk).Error
|
||||||
|
if err != nil {
|
||||||
|
common.SysError(fmt.Sprintf("Find channels not in abilities table failed: %s", err.Error()))
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
channels = append(channels, channelsChunk...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
err := channel.UpdateAbilities(nil)
|
err := channel.UpdateAbilities(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ var channelsIDM map[int]*Channel
|
|||||||
var channelSyncLock sync.RWMutex
|
var channelSyncLock sync.RWMutex
|
||||||
|
|
||||||
func InitChannelCache() {
|
func InitChannelCache() {
|
||||||
|
if !common.MemoryCacheEnabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
newChannelId2channel := make(map[int]*Channel)
|
newChannelId2channel := make(map[int]*Channel)
|
||||||
var channels []*Channel
|
var channels []*Channel
|
||||||
DB.Where("status = ?", common.ChannelStatusEnabled).Find(&channels)
|
DB.Where("status = ?", common.ChannelStatusEnabled).Find(&channels)
|
||||||
|
|||||||
@@ -46,6 +46,17 @@ func (channel *Channel) GetModels() []string {
|
|||||||
return strings.Split(strings.Trim(channel.Models, ","), ",")
|
return strings.Split(strings.Trim(channel.Models, ","), ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) GetGroups() []string {
|
||||||
|
if channel.Group == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
groups := strings.Split(strings.Trim(channel.Group, ","), ",")
|
||||||
|
for i, group := range groups {
|
||||||
|
groups[i] = strings.TrimSpace(group)
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
func (channel *Channel) GetOtherInfo() map[string]interface{} {
|
func (channel *Channel) GetOtherInfo() map[string]interface{} {
|
||||||
otherInfo := make(map[string]interface{})
|
otherInfo := make(map[string]interface{})
|
||||||
if channel.OtherInfo != "" {
|
if channel.OtherInfo != "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user