发布 0.3.0:恢复 Chat 接口并增强云端事件通知
This commit is contained in:
@@ -16,7 +16,6 @@ import (
|
||||
type tenantDeleteResult struct {
|
||||
config model.OciConfig
|
||||
deletedTaskIDs []uint
|
||||
alertRuleIDs []uint
|
||||
channelsGone bool
|
||||
}
|
||||
|
||||
@@ -48,7 +47,7 @@ func (s *OciConfigService) deleteTenantInTx(tx *gorm.DB, id uint, result *tenant
|
||||
if err := s.deleteTenantTasks(tx, id, result); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteTenantEvents(tx, id, result); err != nil {
|
||||
if err := deleteTenantEvents(tx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteTenantAI(tx, id, result); err != nil {
|
||||
@@ -205,17 +204,9 @@ func resetTenantTask(tx *gorm.DB, action tenantTaskAction) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteTenantEvents(tx *gorm.DB, id uint, result *tenantDeleteResult) error {
|
||||
ruleIDs, affectedRules, err := loadTenantEventRefs(tx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteAlertHits(tx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
result.alertRuleIDs = mergeIDs(ruleIDs, affectedRules)
|
||||
if err := deleteWhere(tx, &model.AlertRule{}, "oci_config_id = ?", id); err != nil {
|
||||
return fmt.Errorf("delete tenant alert rules: %w", err)
|
||||
func deleteTenantEvents(tx *gorm.DB, id uint) error {
|
||||
if err := lockTenantEventRows(tx, id); err != nil {
|
||||
return fmt.Errorf("load tenant log events: %w", err)
|
||||
}
|
||||
if err := deleteWhere(tx, &model.LogEvent{}, "oci_config_id = ?", id); err != nil {
|
||||
return fmt.Errorf("delete tenant log events: %w", err)
|
||||
@@ -223,84 +214,15 @@ func deleteTenantEvents(tx *gorm.DB, id uint, result *tenantDeleteResult) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadTenantEventRefs(tx *gorm.DB, id uint) ([]uint, []uint, error) {
|
||||
ruleIDs, err := lockedTenantRuleIDs(tx, id)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("load tenant alert rules: %w", err)
|
||||
}
|
||||
if err := lockTenantEventRows(tx, id); err != nil {
|
||||
return nil, nil, fmt.Errorf("load tenant log events: %w", err)
|
||||
}
|
||||
affected, err := alertHitRuleIDs(tx, id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return ruleIDs, affected, nil
|
||||
}
|
||||
|
||||
func lockedTenantRuleIDs(tx *gorm.DB, id uint) ([]uint, error) {
|
||||
var rows []model.AlertRule
|
||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Select("id").
|
||||
Where("oci_config_id = ?", id).Order("id").Find(&rows).Error
|
||||
ids := make([]uint, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
ids = append(ids, row.ID)
|
||||
}
|
||||
return ids, err
|
||||
}
|
||||
|
||||
// lockTenantEventRows 对租户全部日志事件行加 FOR UPDATE 锁(SQLite 忽略,
|
||||
// MySQL/PG 阻塞并发命中写入);事件可达数万,ID 不再回传拼接 SQL,
|
||||
// 后续删除与关联查询一律用子查询,避免绑定变量上限。
|
||||
// MySQL/PG 阻塞并发写入);事件可达数万,ID 不回传拼接 SQL,删除用条件语句,
|
||||
// 避免绑定变量上限。
|
||||
func lockTenantEventRows(tx *gorm.DB, id uint) error {
|
||||
var rows []model.LogEvent
|
||||
return tx.Clauses(clause.Locking{Strength: "UPDATE"}).Select("id").
|
||||
Where("oci_config_id = ?", id).Order("id").Find(&rows).Error
|
||||
}
|
||||
|
||||
// tenantEventIDs 构造「本租户日志事件 ID」子查询,供 IN (?) 内联。
|
||||
func tenantEventIDs(tx *gorm.DB, id uint) *gorm.DB {
|
||||
return tx.Model(&model.LogEvent{}).Select("id").Where("oci_config_id = ?", id)
|
||||
}
|
||||
|
||||
// alertHitRuleIDs 找出命中引用了本租户事件的规则 ID(去重,可能含他租户/全局规则)。
|
||||
func alertHitRuleIDs(tx *gorm.DB, id uint) ([]uint, error) {
|
||||
ids := make([]uint, 0)
|
||||
err := tx.Model(&model.AlertRuleHit{}).Where("log_event_id IN (?)", tenantEventIDs(tx, id)).
|
||||
Distinct().Pluck("rule_id", &ids).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load affected alert rules: %w", err)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func mergeIDs(groups ...[]uint) []uint {
|
||||
seen := make(map[uint]struct{})
|
||||
out := make([]uint, 0)
|
||||
for _, ids := range groups {
|
||||
for _, id := range ids {
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
out = append(out, id)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// deleteAlertHits 删除本租户相关的全部命中:规则属于本租户,或命中引用了
|
||||
// 本租户的日志事件(他租户/全局规则命中本租户事件的行一并清)。
|
||||
func deleteAlertHits(tx *gorm.DB, id uint) error {
|
||||
rules := tx.Model(&model.AlertRule{}).Select("id").Where("oci_config_id = ?", id)
|
||||
err := tx.Where("rule_id IN (?) OR log_event_id IN (?)", rules, tenantEventIDs(tx, id)).
|
||||
Delete(&model.AlertRuleHit{}).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete tenant alert hits: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteTenantAI(tx *gorm.DB, id uint, result *tenantDeleteResult) error {
|
||||
channelIDs, err := lockedAiChannelIDs(tx, id)
|
||||
if err != nil {
|
||||
@@ -451,9 +373,6 @@ func (s *OciConfigService) afterTenantDelete(ctx context.Context, result *tenant
|
||||
if client, ok := s.client.(tenancyCacheInvalidator); ok {
|
||||
client.InvalidateTenancy(result.config.TenancyOCID)
|
||||
}
|
||||
if s.cleanupEvents != nil {
|
||||
s.cleanupEvents.ClearAlertCooldown(result.alertRuleIDs)
|
||||
}
|
||||
if s.cleanupTasks != nil {
|
||||
s.cleanupTasks.ApplyTenantCleanup(ctx, result.deletedTaskIDs, result.channelsGone)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user