@@ -2,6 +2,7 @@ package services
22
33import (
44 "context"
5+ "sync"
56
67 app_errors "gpt-load/internal/errors"
78 "gpt-load/internal/models"
@@ -108,7 +109,7 @@ func (s *AggregateGroupService) ValidateSubGroups(ctx context.Context, channelTy
108109 }, nil
109110}
110111
111- // GetSubGroups returns sub groups for an aggregate group
112+ // GetSubGroups returns sub groups for an aggregate group with complete information
112113func (s * AggregateGroupService ) GetSubGroups (ctx context.Context , groupID uint ) ([]models.SubGroupInfo , error ) {
113114 var group models.Group
114115 if err := s .db .WithContext (ctx ).First (& group , groupID ).Error ; err != nil {
@@ -144,13 +145,24 @@ func (s *AggregateGroupService) GetSubGroups(ctx context.Context, groupID uint)
144145 return nil , err
145146 }
146147
148+ keyStatsMap := s .fetchSubGroupsKeyStats (ctx , subGroupIDs )
149+
147150 subGroups := make ([]models.SubGroupInfo , 0 , len (subGroupModels ))
148151 for _ , subGroup := range subGroupModels {
152+ stats := keyStatsMap [subGroup .ID ]
153+
154+ if stats .Err != nil {
155+ logrus .WithContext (ctx ).WithError (stats .Err ).
156+ WithField ("group_id" , subGroup .ID ).
157+ Warn ("failed to fetch key stats for sub-group, using zero values" )
158+ }
159+
149160 subGroups = append (subGroups , models.SubGroupInfo {
150- GroupID : subGroup .ID ,
151- Name : subGroup .Name ,
152- DisplayName : subGroup .DisplayName ,
161+ Group : subGroup ,
153162 Weight : weightMap [subGroup .ID ],
163+ TotalKeys : stats .TotalKeys ,
164+ ActiveKeys : stats .ActiveKeys ,
165+ InvalidKeys : stats .InvalidKeys ,
154166 })
155167 }
156168
@@ -365,3 +377,62 @@ func (s *AggregateGroupService) GetParentAggregateGroups(ctx context.Context, su
365377
366378 return parentGroups , nil
367379}
380+
381+ // keyStatsResult stores key statistics for a single group
382+ type keyStatsResult struct {
383+ GroupID uint
384+ TotalKeys int64
385+ ActiveKeys int64
386+ InvalidKeys int64
387+ Err error
388+ }
389+
390+ // fetchSubGroupsKeyStats batch fetches key statistics for multiple sub-groups concurrently
391+ func (s * AggregateGroupService ) fetchSubGroupsKeyStats (ctx context.Context , groupIDs []uint ) map [uint ]keyStatsResult {
392+ results := make (map [uint ]keyStatsResult )
393+ var mu sync.Mutex
394+ var wg sync.WaitGroup
395+
396+ for _ , groupID := range groupIDs {
397+ wg .Add (1 )
398+ go func (gid uint ) {
399+ defer wg .Done ()
400+
401+ var totalKeys , activeKeys int64
402+ result := keyStatsResult {GroupID : gid }
403+
404+ // Query total keys
405+ if err := s .db .WithContext (ctx ).Model (& models.APIKey {}).
406+ Where ("group_id = ?" , gid ).
407+ Count (& totalKeys ).Error ; err != nil {
408+ result .Err = err
409+ mu .Lock ()
410+ results [gid ] = result
411+ mu .Unlock ()
412+ return
413+ }
414+
415+ // Query active keys
416+ if err := s .db .WithContext (ctx ).Model (& models.APIKey {}).
417+ Where ("group_id = ? AND status = ?" , gid , models .KeyStatusActive ).
418+ Count (& activeKeys ).Error ; err != nil {
419+ result .Err = err
420+ mu .Lock ()
421+ results [gid ] = result
422+ mu .Unlock ()
423+ return
424+ }
425+
426+ result .TotalKeys = totalKeys
427+ result .ActiveKeys = activeKeys
428+ result .InvalidKeys = totalKeys - activeKeys
429+
430+ mu .Lock ()
431+ results [gid ] = result
432+ mu .Unlock ()
433+ }(groupID )
434+ }
435+
436+ wg .Wait ()
437+ return results
438+ }
0 commit comments