fix: cap CPU and avoid heavy startup work

This commit is contained in:
ShukeBta
2026-06-11 19:48:00 +08:00
parent d9f87c61b6
commit 7274ea19b7
13 changed files with 230 additions and 35 deletions
+64
View File
@@ -5,15 +5,18 @@ import (
"encoding/json"
"errors"
"fmt"
"path/filepath"
"testing"
"time"
"github.com/glebarez/sqlite"
"github.com/golang-jwt/jwt/v5"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"github.com/ShukeBta/MediaStationGo/internal/config"
"github.com/ShukeBta/MediaStationGo/internal/database"
"github.com/ShukeBta/MediaStationGo/internal/model"
"github.com/ShukeBta/MediaStationGo/internal/repository"
)
@@ -227,6 +230,67 @@ func TestLoginKeepsOnlyConfiguredActiveRefreshTokens(t *testing.T) {
}
}
func TestLoginRetriesTransientSQLiteBusy(t *testing.T) {
ctx := context.Background()
cfg := &config.Config{}
cfg.App.DataDir = t.TempDir()
cfg.Database.DBPath = filepath.Join(cfg.App.DataDir, "busy-login.db")
cfg.Database.WALMode = true
cfg.Database.BusyTimeout = 20
cfg.Database.MaxOpenConns = 4
cfg.Database.MaxIdleConns = 2
cfg.Secrets.JWTSecret = "test-secret"
log := zap.NewNop()
db, err := database.Open(cfg, log)
if err != nil {
t.Fatal(err)
}
sqlDB, err := db.DB()
if err != nil {
t.Fatal(err)
}
defer func() { _ = sqlDB.Close() }()
if err := database.AutoMigrate(db); err != nil {
t.Fatal(err)
}
repos := repository.New(db)
permissions := NewPermissionService(log, repos)
auth := NewAuthService(cfg, log, repos, NewTokenService(cfg, log, repos), permissions)
hash, err := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.MinCost)
if err != nil {
t.Fatal(err)
}
if err := repos.User.Create(ctx, &model.User{
Username: "viewer",
PasswordHash: string(hash),
Role: "user",
Tier: "free",
IsActive: true,
}); err != nil {
t.Fatal(err)
}
tx := repos.DB.Begin()
if err := tx.Exec("UPDATE users SET updated_at = updated_at WHERE username = ?", "viewer").Error; err != nil {
t.Fatal(err)
}
release := make(chan struct{})
go func() {
timer := time.NewTimer(250 * time.Millisecond)
defer timer.Stop()
select {
case <-release:
case <-timer.C:
}
_ = tx.Rollback().Error
}()
defer close(release)
if _, err := auth.Login(ctx, "viewer", "password"); err != nil {
t.Fatalf("login should survive a transient sqlite write lock: %v", err)
}
}
func TestDefaultPermissionsAreViewerOnly(t *testing.T) {
perms := DefaultPermissions("user-1")
if !perms.CanViewDashboard || !perms.CanPlayMedia || !perms.CanExternalPlayer {
-1
View File
@@ -1049,7 +1049,6 @@ func (d *DownloadService) completedTorrentSource(torrent QBitTorrent) string {
for _, candidate := range []string{
torrent.ContentPath,
filepath.Join(torrent.SavePath, torrent.Name),
torrent.SavePath,
} {
clean := strings.TrimSpace(candidate)
if clean == "" || clean == "." {
+20
View File
@@ -87,6 +87,26 @@ func TestDownloadCompleteAutoOrganizesContentPath(t *testing.T) {
}
}
func TestCompletedTorrentSourceDoesNotFallbackToSavePath(t *testing.T) {
root := t.TempDir()
savePath := filepath.Join(root, "downloads", "日番")
if err := os.MkdirAll(savePath, 0o755); err != nil {
t.Fatal(err)
}
svc := NewDownloadService(zap.NewNop(), newOrganizerTestRepo(t), NewHub(zap.NewNop()), nil)
got := svc.completedTorrentSource(QBitTorrent{
Hash: "done123",
Name: "Missing.Payload.S01",
SavePath: savePath,
ContentPath: filepath.Join(savePath, "Missing.Payload.S01", "Missing.Payload.S01E01.mkv"),
})
if got != "" {
t.Fatalf("completedTorrentSource fell back to whole save_path %q; want empty", got)
}
}
func TestDownloadPollBaselinesAlreadyCompletedTorrents(t *testing.T) {
repos := newOrganizerTestRepo(t)
svc := NewDownloadService(zap.NewNop(), repos, NewHub(zap.NewNop()), nil)
+10
View File
@@ -49,6 +49,16 @@ func ApplyRuntimeSetting(cfg *config.Config, key, value string) {
}
cfg.App.FFprobeMaxConcurrent = n
}
case "app.max_cpu_threads", "runtime.max_cpu_threads":
if n, err := strconv.Atoi(value); err == nil {
if n < 1 {
n = 1
}
if n > 8 {
n = 8
}
cfg.App.MaxCPUThreads = n
}
case "transcode.enabled", "transcoder.enabled":
cfg.Transcoder.Enabled = parseBoolSetting(value, true)
case "transcode.hw_enabled", "transcoder.hardware_accel":
+10
View File
@@ -30,4 +30,14 @@ func TestApplyRuntimeSettingTranscodeSwitches(t *testing.T) {
if cfg.Transcoder.MaxConcurrent != 1 {
t.Fatalf("max concurrent = %d, want 1", cfg.Transcoder.MaxConcurrent)
}
ApplyRuntimeSetting(cfg, "app.max_cpu_threads", "99")
if cfg.App.MaxCPUThreads != 8 {
t.Fatalf("max cpu threads = %d, want clamp 8", cfg.App.MaxCPUThreads)
}
ApplyRuntimeSetting(cfg, "app.max_cpu_threads", "0")
if cfg.App.MaxCPUThreads != 1 {
t.Fatalf("max cpu threads = %d, want clamp 1", cfg.App.MaxCPUThreads)
}
}