Merge pull request #754 from xvhuan/perf/admin-core-large-dataset
perf(admin): 优化后台大数据场景加载性能(仪表盘/用户/账号/Ops)
This commit is contained in:
@@ -31,6 +31,10 @@ func (s *OpsService) GetDashboardOverview(ctx context.Context, filter *OpsDashbo
|
||||
filter.QueryMode = s.resolveOpsQueryMode(ctx, filter.QueryMode)
|
||||
|
||||
overview, err := s.opsRepo.GetDashboardOverview(ctx, filter)
|
||||
if err != nil && shouldFallbackOpsPreagg(filter, err) {
|
||||
rawFilter := cloneOpsFilterWithMode(filter, OpsQueryModeRaw)
|
||||
overview, err = s.opsRepo.GetDashboardOverview(ctx, rawFilter)
|
||||
}
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrOpsPreaggregatedNotPopulated) {
|
||||
return nil, infraerrors.Conflict("OPS_PREAGG_NOT_READY", "Pre-aggregated ops metrics are not populated yet")
|
||||
|
||||
@@ -22,7 +22,14 @@ func (s *OpsService) GetErrorTrend(ctx context.Context, filter *OpsDashboardFilt
|
||||
if filter.StartTime.After(filter.EndTime) {
|
||||
return nil, infraerrors.BadRequest("OPS_TIME_RANGE_INVALID", "start_time must be <= end_time")
|
||||
}
|
||||
return s.opsRepo.GetErrorTrend(ctx, filter, bucketSeconds)
|
||||
filter.QueryMode = s.resolveOpsQueryMode(ctx, filter.QueryMode)
|
||||
|
||||
result, err := s.opsRepo.GetErrorTrend(ctx, filter, bucketSeconds)
|
||||
if err != nil && shouldFallbackOpsPreagg(filter, err) {
|
||||
rawFilter := cloneOpsFilterWithMode(filter, OpsQueryModeRaw)
|
||||
return s.opsRepo.GetErrorTrend(ctx, rawFilter, bucketSeconds)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpsService) GetErrorDistribution(ctx context.Context, filter *OpsDashboardFilter) (*OpsErrorDistributionResponse, error) {
|
||||
@@ -41,5 +48,12 @@ func (s *OpsService) GetErrorDistribution(ctx context.Context, filter *OpsDashbo
|
||||
if filter.StartTime.After(filter.EndTime) {
|
||||
return nil, infraerrors.BadRequest("OPS_TIME_RANGE_INVALID", "start_time must be <= end_time")
|
||||
}
|
||||
return s.opsRepo.GetErrorDistribution(ctx, filter)
|
||||
filter.QueryMode = s.resolveOpsQueryMode(ctx, filter.QueryMode)
|
||||
|
||||
result, err := s.opsRepo.GetErrorDistribution(ctx, filter)
|
||||
if err != nil && shouldFallbackOpsPreagg(filter, err) {
|
||||
rawFilter := cloneOpsFilterWithMode(filter, OpsQueryModeRaw)
|
||||
return s.opsRepo.GetErrorDistribution(ctx, rawFilter)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -22,5 +22,12 @@ func (s *OpsService) GetLatencyHistogram(ctx context.Context, filter *OpsDashboa
|
||||
if filter.StartTime.After(filter.EndTime) {
|
||||
return nil, infraerrors.BadRequest("OPS_TIME_RANGE_INVALID", "start_time must be <= end_time")
|
||||
}
|
||||
return s.opsRepo.GetLatencyHistogram(ctx, filter)
|
||||
filter.QueryMode = s.resolveOpsQueryMode(ctx, filter.QueryMode)
|
||||
|
||||
result, err := s.opsRepo.GetLatencyHistogram(ctx, filter)
|
||||
if err != nil && shouldFallbackOpsPreagg(filter, err) {
|
||||
rawFilter := cloneOpsFilterWithMode(filter, OpsQueryModeRaw)
|
||||
return s.opsRepo.GetLatencyHistogram(ctx, rawFilter)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -38,3 +38,18 @@ func (m OpsQueryMode) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func shouldFallbackOpsPreagg(filter *OpsDashboardFilter, err error) bool {
|
||||
return filter != nil &&
|
||||
filter.QueryMode == OpsQueryModeAuto &&
|
||||
errors.Is(err, ErrOpsPreaggregatedNotPopulated)
|
||||
}
|
||||
|
||||
func cloneOpsFilterWithMode(filter *OpsDashboardFilter, mode OpsQueryMode) *OpsDashboardFilter {
|
||||
if filter == nil {
|
||||
return nil
|
||||
}
|
||||
cloned := *filter
|
||||
cloned.QueryMode = mode
|
||||
return &cloned
|
||||
}
|
||||
|
||||
@@ -22,5 +22,13 @@ func (s *OpsService) GetThroughputTrend(ctx context.Context, filter *OpsDashboar
|
||||
if filter.StartTime.After(filter.EndTime) {
|
||||
return nil, infraerrors.BadRequest("OPS_TIME_RANGE_INVALID", "start_time must be <= end_time")
|
||||
}
|
||||
return s.opsRepo.GetThroughputTrend(ctx, filter, bucketSeconds)
|
||||
|
||||
filter.QueryMode = s.resolveOpsQueryMode(ctx, filter.QueryMode)
|
||||
|
||||
result, err := s.opsRepo.GetThroughputTrend(ctx, filter, bucketSeconds)
|
||||
if err != nil && shouldFallbackOpsPreagg(filter, err) {
|
||||
rawFilter := cloneOpsFilterWithMode(filter, OpsQueryModeRaw)
|
||||
return s.opsRepo.GetThroughputTrend(ctx, rawFilter, bucketSeconds)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ type UserListFilters struct {
|
||||
Role string // User role filter
|
||||
Search string // Search in email, username
|
||||
Attributes map[int64]string // Custom attribute filters: attributeID -> value
|
||||
// IncludeSubscriptions controls whether ListWithFilters should load active subscriptions.
|
||||
// For large datasets this can be expensive; admin list pages should enable it on demand.
|
||||
// nil means not specified (default: load subscriptions for backward compatibility).
|
||||
IncludeSubscriptions *bool
|
||||
}
|
||||
|
||||
type UserRepository interface {
|
||||
|
||||
Reference in New Issue
Block a user