diff --git a/src/LiveRecorder.Application/Services/DashboardService.cs b/src/LiveRecorder.Application/Services/DashboardService.cs index 26dea25..681d9ba 100644 --- a/src/LiveRecorder.Application/Services/DashboardService.cs +++ b/src/LiveRecorder.Application/Services/DashboardService.cs @@ -44,48 +44,34 @@ public sealed class DashboardService var todayUtcEnd = new DateTimeOffset(todayBeijingDate.ToDateTime(TimeOnly.MaxValue), ChinaTime.Zone.GetUtcOffset(beijingNow.DateTime)); var recentErrorSince = now.AddHours(-24); - // Run independent queries in parallel for efficiency - var activeRecordingTask = _recordSessionRepository.CountByStatusAsync(RecordSessionStatus.Running, cancellationToken); - var liveRoomCountTask = _liveRoomRepository.CountByAvailabilityAsync(LiveRoomAvailabilityStatus.Live, cancellationToken); - var offlineRoomCountTask = _liveRoomRepository.CountByAvailabilityAsync(LiveRoomAvailabilityStatus.Offline, cancellationToken); - var totalRoomCountTask = _liveRoomRepository.CountAsync(cancellationToken); - var activeSessionCountTask = _recordSessionRepository.CountActiveAsync(cancellationToken); - var recentErrorCountTask = _systemLogRepository.CountRecentErrorsAsync(recentErrorSince, cancellationToken); - var todayDurationTask = _recordTaskRepository.SumDurationSecondsAsync(todayUtcStart, todayUtcEnd, cancellationToken); - var todayAggregateTask = _recordResultRepository.GetTodayAggregateAsync(todayUtcStart, todayUtcEnd, cancellationToken); - var recentSessionsTask = _recordSessionRepository.ListRecentAsync(5, cancellationToken); - var todaySessionsTask = _recordSessionRepository.ListInDateRangeAsync(todayUtcStart, todayUtcEnd, cancellationToken); - var settingsTask = _systemSettingsService.GetAsync(cancellationToken); - - await Task.WhenAll( - activeRecordingTask, - liveRoomCountTask, - offlineRoomCountTask, - totalRoomCountTask, - activeSessionCountTask, - recentErrorCountTask, - todayDurationTask, - todayAggregateTask, - recentSessionsTask, - todaySessionsTask, - (Task)settingsTask - ); - - var (todayTotalBytes, todayTotalDanmaku) = todayAggregateTask.Result; - var settings = settingsTask.Result; + // Run queries sequentially — DbContext is not thread-safe + var activeRecordingCount = await _recordSessionRepository.CountByStatusAsync(RecordSessionStatus.Running, cancellationToken); + var liveRoomCount = await _liveRoomRepository.CountByAvailabilityAsync(LiveRoomAvailabilityStatus.Live, cancellationToken); + var offlineRoomCount = await _liveRoomRepository.CountByAvailabilityAsync(LiveRoomAvailabilityStatus.Offline, cancellationToken); + var totalRoomCount = await _liveRoomRepository.CountAsync(cancellationToken); + var activeSessionCount = await _recordSessionRepository.CountActiveAsync(cancellationToken); + var recentErrorCount = await _systemLogRepository.CountRecentErrorsAsync(recentErrorSince, cancellationToken); + var todayRecordingSeconds = await _recordTaskRepository.SumDurationSecondsAsync(todayUtcStart, todayUtcEnd, cancellationToken); + var (todayTotalBytes, todayTotalDanmaku) = await _recordResultRepository.GetTodayAggregateAsync(todayUtcStart, todayUtcEnd, cancellationToken); + var recentSessions = await _recordSessionRepository.ListRecentAsync(5, cancellationToken); + var todaySessions = await _recordSessionRepository.ListInDateRangeAsync(todayUtcStart, todayUtcEnd, cancellationToken); + var settings = await _systemSettingsService.GetAsync(cancellationToken); var storageCheck = _storageGuardService.CheckCanStartOrResume(settings); + var pendingTranscodeCount = await _recordTaskRepository.CountByStatusAsync(RecordTaskStatus.Processing, cancellationToken); + var pendingUploadCount = await _recordResultRepository.CountPendingUploadAsync(cancellationToken); + var queuedDataBytes = await _recordResultRepository.SumPendingUploadBytesAsync(cancellationToken); return new DashboardDto { - ActiveRecordingCount = activeRecordingTask.Result, - LiveRoomCount = liveRoomCountTask.Result, - OfflineRoomCount = offlineRoomCountTask.Result, - TotalRoomCount = totalRoomCountTask.Result, - TodayRecordingSeconds = todayDurationTask.Result, + ActiveRecordingCount = activeRecordingCount, + LiveRoomCount = liveRoomCount, + OfflineRoomCount = offlineRoomCount, + TotalRoomCount = totalRoomCount, + TodayRecordingSeconds = todayRecordingSeconds, TodayDataBytes = todayTotalBytes, TodayDanmakuCount = todayTotalDanmaku, - ActiveSessionCount = activeSessionCountTask.Result, - RecentErrorCount = recentErrorCountTask.Result, + ActiveSessionCount = activeSessionCount, + RecentErrorCount = recentErrorCount, StorageStatus = new StorageStatusDto { HasEnoughSpace = storageCheck.HasEnoughSpace, @@ -94,13 +80,13 @@ public sealed class DashboardService Tier = storageCheck.Tier.ToString(), UsagePercent = storageCheck.UsagePercent }, - PendingTranscodeCount = await _recordTaskRepository.CountByStatusAsync(Domain.Enums.RecordTaskStatus.Processing, cancellationToken), - PendingUploadCount = await _recordResultRepository.CountPendingUploadAsync(cancellationToken), - QueuedDataBytes = await _recordResultRepository.SumPendingUploadBytesAsync(cancellationToken), - RecentSessions = recentSessionsTask.Result + PendingTranscodeCount = pendingTranscodeCount, + PendingUploadCount = pendingUploadCount, + QueuedDataBytes = queuedDataBytes, + RecentSessions = recentSessions .Select(MapRecentSession) .ToList(), - TopRooms = ComputeTopRooms(todaySessionsTask.Result) + TopRooms = ComputeTopRooms(todaySessions) }; }