Commit 8cf83c98 authored by erio's avatar erio
Browse files

feat(channel-monitor): aggregate history to daily rollups + soft delete

明细只保留 1 天,超过 1 天聚合到新表 channel_monitor_daily_rollups(按
monitor_id/model/bucket_date 维度),聚合保留 30 天。两张表都用 SoftDeleteMixin
软删除(DELETE 自动改为 UPDATE deleted_at = NOW())。

聚合 + 清理任务由 OpsCleanupService 的 cron 统一调度,与运维监控的清理共享
schedule(默认 0 2 * * *)和 leader lock。ChannelMonitorRunner 的 cleanupLoop
被移除,只保留 dueCheckLoop。

读取路径 ComputeAvailability* 改为 UNION 明细(今天 deleted_at IS NULL)+
聚合(过去 windowDays 天 deleted_at IS NULL),SUM(ok)/SUM(total) 自然加权
计算可用率,AVG latency 用 SUM(sum_latency_ms)/SUM(count_latency)。

watermark 表 channel_monitor_aggregation_watermark 单行(id=1),记录
last_aggregated_date,重启后从该日期 +1 继续聚合,首次为 nil 则从
today - 30d 开始回填,单次最多 35 天上限避免长事务。

raw SQL 的 ListLatestPerModel / ListLatestForMonitorIDs / ListRecentHistoryForMonitors
都补上 deleted_at IS NULL 过滤(SoftDeleteMixin interceptor 只对 ent query 生效)。

bump version to 0.1.114.28

GroupBadge 在 MonitorKeyPickerDialog 中复用平台主题色 + 倍率/专属倍率
(顺手优化)。
parent ba98243c
This diff is collapsed.
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentity"
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
"github.com/Wei-Shaw/sub2api/ent/channelmonitor" "github.com/Wei-Shaw/sub2api/ent/channelmonitor"
"github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup"
"github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/group"
...@@ -104,38 +105,39 @@ var ( ...@@ -104,38 +105,39 @@ var (
func checkColumn(t, c string) error { func checkColumn(t, c string) error {
initCheck.Do(func() { initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
apikey.Table: apikey.ValidColumn, apikey.Table: apikey.ValidColumn,
account.Table: account.ValidColumn, account.Table: account.ValidColumn,
accountgroup.Table: accountgroup.ValidColumn, accountgroup.Table: accountgroup.ValidColumn,
announcement.Table: announcement.ValidColumn, announcement.Table: announcement.ValidColumn,
announcementread.Table: announcementread.ValidColumn, announcementread.Table: announcementread.ValidColumn,
authidentity.Table: authidentity.ValidColumn, authidentity.Table: authidentity.ValidColumn,
authidentitychannel.Table: authidentitychannel.ValidColumn, authidentitychannel.Table: authidentitychannel.ValidColumn,
channelmonitor.Table: channelmonitor.ValidColumn, channelmonitor.Table: channelmonitor.ValidColumn,
channelmonitorhistory.Table: channelmonitorhistory.ValidColumn, channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn,
errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, channelmonitorhistory.Table: channelmonitorhistory.ValidColumn,
group.Table: group.ValidColumn, errorpassthroughrule.Table: errorpassthroughrule.ValidColumn,
idempotencyrecord.Table: idempotencyrecord.ValidColumn, group.Table: group.ValidColumn,
identityadoptiondecision.Table: identityadoptiondecision.ValidColumn, idempotencyrecord.Table: idempotencyrecord.ValidColumn,
paymentauditlog.Table: paymentauditlog.ValidColumn, identityadoptiondecision.Table: identityadoptiondecision.ValidColumn,
paymentorder.Table: paymentorder.ValidColumn, paymentauditlog.Table: paymentauditlog.ValidColumn,
paymentproviderinstance.Table: paymentproviderinstance.ValidColumn, paymentorder.Table: paymentorder.ValidColumn,
pendingauthsession.Table: pendingauthsession.ValidColumn, paymentproviderinstance.Table: paymentproviderinstance.ValidColumn,
promocode.Table: promocode.ValidColumn, pendingauthsession.Table: pendingauthsession.ValidColumn,
promocodeusage.Table: promocodeusage.ValidColumn, promocode.Table: promocode.ValidColumn,
proxy.Table: proxy.ValidColumn, promocodeusage.Table: promocodeusage.ValidColumn,
redeemcode.Table: redeemcode.ValidColumn, proxy.Table: proxy.ValidColumn,
securitysecret.Table: securitysecret.ValidColumn, redeemcode.Table: redeemcode.ValidColumn,
setting.Table: setting.ValidColumn, securitysecret.Table: securitysecret.ValidColumn,
subscriptionplan.Table: subscriptionplan.ValidColumn, setting.Table: setting.ValidColumn,
tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn, subscriptionplan.Table: subscriptionplan.ValidColumn,
usagecleanuptask.Table: usagecleanuptask.ValidColumn, tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn,
usagelog.Table: usagelog.ValidColumn, usagecleanuptask.Table: usagecleanuptask.ValidColumn,
user.Table: user.ValidColumn, usagelog.Table: usagelog.ValidColumn,
userallowedgroup.Table: userallowedgroup.ValidColumn, user.Table: user.ValidColumn,
userattributedefinition.Table: userattributedefinition.ValidColumn, userallowedgroup.Table: userallowedgroup.ValidColumn,
userattributevalue.Table: userattributevalue.ValidColumn, userattributedefinition.Table: userattributedefinition.ValidColumn,
usersubscription.Table: usersubscription.ValidColumn, userattributevalue.Table: userattributevalue.ValidColumn,
usersubscription.Table: usersubscription.ValidColumn,
}) })
}) })
return columnCheck(t, c) return columnCheck(t, c)
......
...@@ -105,6 +105,18 @@ func (f ChannelMonitorFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Val ...@@ -105,6 +105,18 @@ func (f ChannelMonitorFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Val
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorMutation", m) return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorMutation", m)
} }
// The ChannelMonitorDailyRollupFunc type is an adapter to allow the use of ordinary
// function as ChannelMonitorDailyRollup mutator.
type ChannelMonitorDailyRollupFunc func(context.Context, *ent.ChannelMonitorDailyRollupMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f ChannelMonitorDailyRollupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.ChannelMonitorDailyRollupMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorDailyRollupMutation", m)
}
// The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary // The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary
// function as ChannelMonitorHistory mutator. // function as ChannelMonitorHistory mutator.
type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryMutation) (ent.Value, error) type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryMutation) (ent.Value, error)
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentity"
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
"github.com/Wei-Shaw/sub2api/ent/channelmonitor" "github.com/Wei-Shaw/sub2api/ent/channelmonitor"
"github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup"
"github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/group"
...@@ -315,6 +316,33 @@ func (f TraverseChannelMonitor) Traverse(ctx context.Context, q ent.Query) error ...@@ -315,6 +316,33 @@ func (f TraverseChannelMonitor) Traverse(ctx context.Context, q ent.Query) error
return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorQuery", q) return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorQuery", q)
} }
// The ChannelMonitorDailyRollupFunc type is an adapter to allow the use of ordinary function as a Querier.
type ChannelMonitorDailyRollupFunc func(context.Context, *ent.ChannelMonitorDailyRollupQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f ChannelMonitorDailyRollupFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.ChannelMonitorDailyRollupQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorDailyRollupQuery", q)
}
// The TraverseChannelMonitorDailyRollup type is an adapter to allow the use of ordinary function as Traverser.
type TraverseChannelMonitorDailyRollup func(context.Context, *ent.ChannelMonitorDailyRollupQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseChannelMonitorDailyRollup) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseChannelMonitorDailyRollup) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.ChannelMonitorDailyRollupQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorDailyRollupQuery", q)
}
// The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary function as a Querier. // The ChannelMonitorHistoryFunc type is an adapter to allow the use of ordinary function as a Querier.
type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryQuery) (ent.Value, error) type ChannelMonitorHistoryFunc func(context.Context, *ent.ChannelMonitorHistoryQuery) (ent.Value, error)
...@@ -982,6 +1010,8 @@ func NewQuery(q ent.Query) (Query, error) { ...@@ -982,6 +1010,8 @@ func NewQuery(q ent.Query) (Query, error) {
return &query[*ent.AuthIdentityChannelQuery, predicate.AuthIdentityChannel, authidentitychannel.OrderOption]{typ: ent.TypeAuthIdentityChannel, tq: q}, nil return &query[*ent.AuthIdentityChannelQuery, predicate.AuthIdentityChannel, authidentitychannel.OrderOption]{typ: ent.TypeAuthIdentityChannel, tq: q}, nil
case *ent.ChannelMonitorQuery: case *ent.ChannelMonitorQuery:
return &query[*ent.ChannelMonitorQuery, predicate.ChannelMonitor, channelmonitor.OrderOption]{typ: ent.TypeChannelMonitor, tq: q}, nil return &query[*ent.ChannelMonitorQuery, predicate.ChannelMonitor, channelmonitor.OrderOption]{typ: ent.TypeChannelMonitor, tq: q}, nil
case *ent.ChannelMonitorDailyRollupQuery:
return &query[*ent.ChannelMonitorDailyRollupQuery, predicate.ChannelMonitorDailyRollup, channelmonitordailyrollup.OrderOption]{typ: ent.TypeChannelMonitorDailyRollup, tq: q}, nil
case *ent.ChannelMonitorHistoryQuery: case *ent.ChannelMonitorHistoryQuery:
return &query[*ent.ChannelMonitorHistoryQuery, predicate.ChannelMonitorHistory, channelmonitorhistory.OrderOption]{typ: ent.TypeChannelMonitorHistory, tq: q}, nil return &query[*ent.ChannelMonitorHistoryQuery, predicate.ChannelMonitorHistory, channelmonitorhistory.OrderOption]{typ: ent.TypeChannelMonitorHistory, tq: q}, nil
case *ent.ErrorPassthroughRuleQuery: case *ent.ErrorPassthroughRuleQuery:
......
...@@ -461,9 +461,55 @@ var ( ...@@ -461,9 +461,55 @@ var (
}, },
}, },
} }
// ChannelMonitorDailyRollupsColumns holds the columns for the "channel_monitor_daily_rollups" table.
ChannelMonitorDailyRollupsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true},
{Name: "deleted_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "model", Type: field.TypeString, Size: 200},
{Name: "bucket_date", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "date"}},
{Name: "total_checks", Type: field.TypeInt, Default: 0},
{Name: "ok_count", Type: field.TypeInt, Default: 0},
{Name: "operational_count", Type: field.TypeInt, Default: 0},
{Name: "degraded_count", Type: field.TypeInt, Default: 0},
{Name: "failed_count", Type: field.TypeInt, Default: 0},
{Name: "error_count", Type: field.TypeInt, Default: 0},
{Name: "sum_latency_ms", Type: field.TypeInt64, Default: 0},
{Name: "count_latency", Type: field.TypeInt, Default: 0},
{Name: "sum_ping_latency_ms", Type: field.TypeInt64, Default: 0},
{Name: "count_ping_latency", Type: field.TypeInt, Default: 0},
{Name: "computed_at", Type: field.TypeTime},
{Name: "monitor_id", Type: field.TypeInt64},
}
// ChannelMonitorDailyRollupsTable holds the schema information for the "channel_monitor_daily_rollups" table.
ChannelMonitorDailyRollupsTable = &schema.Table{
Name: "channel_monitor_daily_rollups",
Columns: ChannelMonitorDailyRollupsColumns,
PrimaryKey: []*schema.Column{ChannelMonitorDailyRollupsColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "channel_monitor_daily_rollups_channel_monitors_daily_rollups",
Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[15]},
RefColumns: []*schema.Column{ChannelMonitorsColumns[0]},
OnDelete: schema.Cascade,
},
},
Indexes: []*schema.Index{
{
Name: "channelmonitordailyrollup_monitor_id_model_bucket_date",
Unique: true,
Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[15], ChannelMonitorDailyRollupsColumns[2], ChannelMonitorDailyRollupsColumns[3]},
},
{
Name: "channelmonitordailyrollup_bucket_date",
Unique: false,
Columns: []*schema.Column{ChannelMonitorDailyRollupsColumns[3]},
},
},
}
// ChannelMonitorHistoriesColumns holds the columns for the "channel_monitor_histories" table. // ChannelMonitorHistoriesColumns holds the columns for the "channel_monitor_histories" table.
ChannelMonitorHistoriesColumns = []*schema.Column{ ChannelMonitorHistoriesColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true}, {Name: "id", Type: field.TypeInt64, Increment: true},
{Name: "deleted_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "model", Type: field.TypeString, Size: 200}, {Name: "model", Type: field.TypeString, Size: 200},
{Name: "status", Type: field.TypeEnum, Enums: []string{"operational", "degraded", "failed", "error"}}, {Name: "status", Type: field.TypeEnum, Enums: []string{"operational", "degraded", "failed", "error"}},
{Name: "latency_ms", Type: field.TypeInt, Nullable: true}, {Name: "latency_ms", Type: field.TypeInt, Nullable: true},
...@@ -480,7 +526,7 @@ var ( ...@@ -480,7 +526,7 @@ var (
ForeignKeys: []*schema.ForeignKey{ ForeignKeys: []*schema.ForeignKey{
{ {
Symbol: "channel_monitor_histories_channel_monitors_history", Symbol: "channel_monitor_histories_channel_monitors_history",
Columns: []*schema.Column{ChannelMonitorHistoriesColumns[7]}, Columns: []*schema.Column{ChannelMonitorHistoriesColumns[8]},
RefColumns: []*schema.Column{ChannelMonitorsColumns[0]}, RefColumns: []*schema.Column{ChannelMonitorsColumns[0]},
OnDelete: schema.Cascade, OnDelete: schema.Cascade,
}, },
...@@ -489,12 +535,12 @@ var ( ...@@ -489,12 +535,12 @@ var (
{ {
Name: "channelmonitorhistory_monitor_id_model_checked_at", Name: "channelmonitorhistory_monitor_id_model_checked_at",
Unique: false, Unique: false,
Columns: []*schema.Column{ChannelMonitorHistoriesColumns[7], ChannelMonitorHistoriesColumns[1], ChannelMonitorHistoriesColumns[6]}, Columns: []*schema.Column{ChannelMonitorHistoriesColumns[8], ChannelMonitorHistoriesColumns[2], ChannelMonitorHistoriesColumns[7]},
}, },
{ {
Name: "channelmonitorhistory_checked_at", Name: "channelmonitorhistory_checked_at",
Unique: false, Unique: false,
Columns: []*schema.Column{ChannelMonitorHistoriesColumns[6]}, Columns: []*schema.Column{ChannelMonitorHistoriesColumns[7]},
}, },
}, },
} }
...@@ -1598,6 +1644,7 @@ var ( ...@@ -1598,6 +1644,7 @@ var (
AuthIdentitiesTable, AuthIdentitiesTable,
AuthIdentityChannelsTable, AuthIdentityChannelsTable,
ChannelMonitorsTable, ChannelMonitorsTable,
ChannelMonitorDailyRollupsTable,
ChannelMonitorHistoriesTable, ChannelMonitorHistoriesTable,
ErrorPassthroughRulesTable, ErrorPassthroughRulesTable,
GroupsTable, GroupsTable,
...@@ -1659,6 +1706,10 @@ func init() { ...@@ -1659,6 +1706,10 @@ func init() {
ChannelMonitorsTable.Annotation = &entsql.Annotation{ ChannelMonitorsTable.Annotation = &entsql.Annotation{
Table: "channel_monitors", Table: "channel_monitors",
} }
ChannelMonitorDailyRollupsTable.ForeignKeys[0].RefTable = ChannelMonitorsTable
ChannelMonitorDailyRollupsTable.Annotation = &entsql.Annotation{
Table: "channel_monitor_daily_rollups",
}
ChannelMonitorHistoriesTable.ForeignKeys[0].RefTable = ChannelMonitorsTable ChannelMonitorHistoriesTable.ForeignKeys[0].RefTable = ChannelMonitorsTable
ChannelMonitorHistoriesTable.Annotation = &entsql.Annotation{ ChannelMonitorHistoriesTable.Annotation = &entsql.Annotation{
Table: "channel_monitor_histories", Table: "channel_monitor_histories",
......
This diff is collapsed.
...@@ -30,6 +30,9 @@ type AuthIdentityChannel func(*sql.Selector) ...@@ -30,6 +30,9 @@ type AuthIdentityChannel func(*sql.Selector)
// ChannelMonitor is the predicate function for channelmonitor builders. // ChannelMonitor is the predicate function for channelmonitor builders.
type ChannelMonitor func(*sql.Selector) type ChannelMonitor func(*sql.Selector)
// ChannelMonitorDailyRollup is the predicate function for channelmonitordailyrollup builders.
type ChannelMonitorDailyRollup func(*sql.Selector)
// ChannelMonitorHistory is the predicate function for channelmonitorhistory builders. // ChannelMonitorHistory is the predicate function for channelmonitorhistory builders.
type ChannelMonitorHistory func(*sql.Selector) type ChannelMonitorHistory func(*sql.Selector)
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/authidentity" "github.com/Wei-Shaw/sub2api/ent/authidentity"
"github.com/Wei-Shaw/sub2api/ent/authidentitychannel" "github.com/Wei-Shaw/sub2api/ent/authidentitychannel"
"github.com/Wei-Shaw/sub2api/ent/channelmonitor" "github.com/Wei-Shaw/sub2api/ent/channelmonitor"
"github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup"
"github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/group"
...@@ -520,6 +521,82 @@ func init() { ...@@ -520,6 +521,82 @@ func init() {
channelmonitorDescIntervalSeconds := channelmonitorFields[8].Descriptor() channelmonitorDescIntervalSeconds := channelmonitorFields[8].Descriptor()
// channelmonitor.IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save. // channelmonitor.IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save.
channelmonitor.IntervalSecondsValidator = channelmonitorDescIntervalSeconds.Validators[0].(func(int) error) channelmonitor.IntervalSecondsValidator = channelmonitorDescIntervalSeconds.Validators[0].(func(int) error)
channelmonitordailyrollupMixin := schema.ChannelMonitorDailyRollup{}.Mixin()
channelmonitordailyrollupMixinHooks0 := channelmonitordailyrollupMixin[0].Hooks()
channelmonitordailyrollup.Hooks[0] = channelmonitordailyrollupMixinHooks0[0]
channelmonitordailyrollupMixinInters0 := channelmonitordailyrollupMixin[0].Interceptors()
channelmonitordailyrollup.Interceptors[0] = channelmonitordailyrollupMixinInters0[0]
channelmonitordailyrollupFields := schema.ChannelMonitorDailyRollup{}.Fields()
_ = channelmonitordailyrollupFields
// channelmonitordailyrollupDescModel is the schema descriptor for model field.
channelmonitordailyrollupDescModel := channelmonitordailyrollupFields[1].Descriptor()
// channelmonitordailyrollup.ModelValidator is a validator for the "model" field. It is called by the builders before save.
channelmonitordailyrollup.ModelValidator = func() func(string) error {
validators := channelmonitordailyrollupDescModel.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(model string) error {
for _, fn := range fns {
if err := fn(model); err != nil {
return err
}
}
return nil
}
}()
// channelmonitordailyrollupDescTotalChecks is the schema descriptor for total_checks field.
channelmonitordailyrollupDescTotalChecks := channelmonitordailyrollupFields[3].Descriptor()
// channelmonitordailyrollup.DefaultTotalChecks holds the default value on creation for the total_checks field.
channelmonitordailyrollup.DefaultTotalChecks = channelmonitordailyrollupDescTotalChecks.Default.(int)
// channelmonitordailyrollupDescOkCount is the schema descriptor for ok_count field.
channelmonitordailyrollupDescOkCount := channelmonitordailyrollupFields[4].Descriptor()
// channelmonitordailyrollup.DefaultOkCount holds the default value on creation for the ok_count field.
channelmonitordailyrollup.DefaultOkCount = channelmonitordailyrollupDescOkCount.Default.(int)
// channelmonitordailyrollupDescOperationalCount is the schema descriptor for operational_count field.
channelmonitordailyrollupDescOperationalCount := channelmonitordailyrollupFields[5].Descriptor()
// channelmonitordailyrollup.DefaultOperationalCount holds the default value on creation for the operational_count field.
channelmonitordailyrollup.DefaultOperationalCount = channelmonitordailyrollupDescOperationalCount.Default.(int)
// channelmonitordailyrollupDescDegradedCount is the schema descriptor for degraded_count field.
channelmonitordailyrollupDescDegradedCount := channelmonitordailyrollupFields[6].Descriptor()
// channelmonitordailyrollup.DefaultDegradedCount holds the default value on creation for the degraded_count field.
channelmonitordailyrollup.DefaultDegradedCount = channelmonitordailyrollupDescDegradedCount.Default.(int)
// channelmonitordailyrollupDescFailedCount is the schema descriptor for failed_count field.
channelmonitordailyrollupDescFailedCount := channelmonitordailyrollupFields[7].Descriptor()
// channelmonitordailyrollup.DefaultFailedCount holds the default value on creation for the failed_count field.
channelmonitordailyrollup.DefaultFailedCount = channelmonitordailyrollupDescFailedCount.Default.(int)
// channelmonitordailyrollupDescErrorCount is the schema descriptor for error_count field.
channelmonitordailyrollupDescErrorCount := channelmonitordailyrollupFields[8].Descriptor()
// channelmonitordailyrollup.DefaultErrorCount holds the default value on creation for the error_count field.
channelmonitordailyrollup.DefaultErrorCount = channelmonitordailyrollupDescErrorCount.Default.(int)
// channelmonitordailyrollupDescSumLatencyMs is the schema descriptor for sum_latency_ms field.
channelmonitordailyrollupDescSumLatencyMs := channelmonitordailyrollupFields[9].Descriptor()
// channelmonitordailyrollup.DefaultSumLatencyMs holds the default value on creation for the sum_latency_ms field.
channelmonitordailyrollup.DefaultSumLatencyMs = channelmonitordailyrollupDescSumLatencyMs.Default.(int64)
// channelmonitordailyrollupDescCountLatency is the schema descriptor for count_latency field.
channelmonitordailyrollupDescCountLatency := channelmonitordailyrollupFields[10].Descriptor()
// channelmonitordailyrollup.DefaultCountLatency holds the default value on creation for the count_latency field.
channelmonitordailyrollup.DefaultCountLatency = channelmonitordailyrollupDescCountLatency.Default.(int)
// channelmonitordailyrollupDescSumPingLatencyMs is the schema descriptor for sum_ping_latency_ms field.
channelmonitordailyrollupDescSumPingLatencyMs := channelmonitordailyrollupFields[11].Descriptor()
// channelmonitordailyrollup.DefaultSumPingLatencyMs holds the default value on creation for the sum_ping_latency_ms field.
channelmonitordailyrollup.DefaultSumPingLatencyMs = channelmonitordailyrollupDescSumPingLatencyMs.Default.(int64)
// channelmonitordailyrollupDescCountPingLatency is the schema descriptor for count_ping_latency field.
channelmonitordailyrollupDescCountPingLatency := channelmonitordailyrollupFields[12].Descriptor()
// channelmonitordailyrollup.DefaultCountPingLatency holds the default value on creation for the count_ping_latency field.
channelmonitordailyrollup.DefaultCountPingLatency = channelmonitordailyrollupDescCountPingLatency.Default.(int)
// channelmonitordailyrollupDescComputedAt is the schema descriptor for computed_at field.
channelmonitordailyrollupDescComputedAt := channelmonitordailyrollupFields[13].Descriptor()
// channelmonitordailyrollup.DefaultComputedAt holds the default value on creation for the computed_at field.
channelmonitordailyrollup.DefaultComputedAt = channelmonitordailyrollupDescComputedAt.Default.(func() time.Time)
// channelmonitordailyrollup.UpdateDefaultComputedAt holds the default value on update for the computed_at field.
channelmonitordailyrollup.UpdateDefaultComputedAt = channelmonitordailyrollupDescComputedAt.UpdateDefault.(func() time.Time)
channelmonitorhistoryMixin := schema.ChannelMonitorHistory{}.Mixin()
channelmonitorhistoryMixinHooks0 := channelmonitorhistoryMixin[0].Hooks()
channelmonitorhistory.Hooks[0] = channelmonitorhistoryMixinHooks0[0]
channelmonitorhistoryMixinInters0 := channelmonitorhistoryMixin[0].Interceptors()
channelmonitorhistory.Interceptors[0] = channelmonitorhistoryMixinInters0[0]
channelmonitorhistoryFields := schema.ChannelMonitorHistory{}.Fields() channelmonitorhistoryFields := schema.ChannelMonitorHistory{}.Fields()
_ = channelmonitorhistoryFields _ = channelmonitorhistoryFields
// channelmonitorhistoryDescModel is the schema descriptor for model field. // channelmonitorhistoryDescModel is the schema descriptor for model field.
......
...@@ -69,6 +69,8 @@ func (ChannelMonitor) Edges() []ent.Edge { ...@@ -69,6 +69,8 @@ func (ChannelMonitor) Edges() []ent.Edge {
return []ent.Edge{ return []ent.Edge{
edge.To("history", ChannelMonitorHistory.Type). edge.To("history", ChannelMonitorHistory.Type).
Annotations(entsql.OnDelete(entsql.Cascade)), Annotations(entsql.OnDelete(entsql.Cascade)),
edge.To("daily_rollups", ChannelMonitorDailyRollup.Type).
Annotations(entsql.OnDelete(entsql.Cascade)),
} }
} }
......
package schema
import (
"time"
"entgo.io/ent"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
)
// ChannelMonitorDailyRollup 按 (monitor_id, model, bucket_date) 维度聚合的渠道监控日统计。
// 每天的明细被收敛为一行(保留 status 分布 + 延迟和),用于 7d/15d/30d 窗口的可用率
// 加权计算(avg_latency = sum_latency_ms / count_latency;availability = ok_count / total_checks)。
type ChannelMonitorDailyRollup struct {
ent.Schema
}
func (ChannelMonitorDailyRollup) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "channel_monitor_daily_rollups"},
}
}
func (ChannelMonitorDailyRollup) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.SoftDeleteMixin{},
}
}
func (ChannelMonitorDailyRollup) Fields() []ent.Field {
return []ent.Field{
field.Int64("monitor_id"),
field.String("model").
NotEmpty().
MaxLen(200),
field.Time("bucket_date").
SchemaType(map[string]string{dialect.Postgres: "date"}),
field.Int("total_checks").Default(0),
field.Int("ok_count").Default(0),
field.Int("operational_count").Default(0),
field.Int("degraded_count").Default(0),
field.Int("failed_count").Default(0),
field.Int("error_count").Default(0),
field.Int64("sum_latency_ms").Default(0),
field.Int("count_latency").Default(0),
field.Int64("sum_ping_latency_ms").Default(0),
field.Int("count_ping_latency").Default(0),
field.Time("computed_at").Default(time.Now).UpdateDefault(time.Now),
}
}
func (ChannelMonitorDailyRollup) Edges() []ent.Edge {
return []ent.Edge{
edge.From("monitor", ChannelMonitor.Type).
Ref("daily_rollups").
Field("monitor_id").
Unique().
Required(),
}
}
func (ChannelMonitorDailyRollup) Indexes() []ent.Index {
return []ent.Index{
index.Fields("monitor_id", "model", "bucket_date").Unique(),
index.Fields("bucket_date"),
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment