Better termination handling in Scanner's progress

This commit is contained in:
Deluan 2020-11-25 19:05:36 -05:00
parent 3ad36ebd2a
commit f29bb211d1
3 changed files with 36 additions and 31 deletions

View file

@ -4,6 +4,7 @@ import (
"github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/log" "github.com/deluan/navidrome/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context"
) )
var fullRescan bool var fullRescan bool
@ -26,7 +27,7 @@ func runScanner() {
conf.Server.DevPreCacheAlbumArtwork = false conf.Server.DevPreCacheAlbumArtwork = false
scanner := GetScanner() scanner := GetScanner()
_ = scanner.RescanAll(fullRescan) _ = scanner.RescanAll(context.Background(), fullRescan)
if fullRescan { if fullRescan {
log.Info("Finished full rescan") log.Info("Finished full rescan")
} else { } else {

View file

@ -18,7 +18,7 @@ import (
type Scanner interface { type Scanner interface {
Start(interval time.Duration) Start(interval time.Duration)
Stop() Stop()
RescanAll(fullRescan bool) error RescanAll(ctx context.Context, fullRescan bool) error
Status(mediaFolder string) (*StatusInfo, error) Status(mediaFolder string) (*StatusInfo, error)
Scanning() bool Scanning() bool
} }
@ -79,7 +79,7 @@ func (s *scanner) Start(interval time.Duration) {
ticker := time.NewTicker(interval) ticker := time.NewTicker(interval)
defer ticker.Stop() defer ticker.Stop()
for { for {
err := s.RescanAll(false) err := s.RescanAll(context.Background(), false)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
@ -96,7 +96,7 @@ func (s *scanner) Stop() {
s.done <- true s.done <- true
} }
func (s *scanner) rescan(mediaFolder string, fullRescan bool) error { func (s *scanner) rescan(ctx context.Context, mediaFolder string, fullRescan bool) error {
folderScanner := s.folders[mediaFolder] folderScanner := s.folders[mediaFolder]
start := time.Now() start := time.Now()
@ -105,16 +105,16 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
lastModifiedSince := time.Time{} lastModifiedSince := time.Time{}
if !fullRescan { if !fullRescan {
lastModifiedSince = s.getLastModifiedSince(mediaFolder) lastModifiedSince = s.getLastModifiedSince(ctx, mediaFolder)
log.Debug("Scanning folder", "folder", mediaFolder, "lastModifiedSince", lastModifiedSince) log.Debug("Scanning folder", "folder", mediaFolder, "lastModifiedSince", lastModifiedSince)
} else { } else {
log.Debug("Scanning folder (full scan)", "folder", mediaFolder) log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
} }
progress := s.startProgressTracker(mediaFolder) progress, cancel := s.startProgressTracker(mediaFolder)
defer close(progress) defer cancel()
err := folderScanner.Scan(log.NewContext(context.TODO()), lastModifiedSince, progress) err := folderScanner.Scan(ctx, lastModifiedSince, progress)
if err != nil { if err != nil {
log.Error("Error importing MediaFolder", "folder", mediaFolder, err) log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
} }
@ -123,7 +123,8 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
return err return err
} }
func (s *scanner) startProgressTracker(mediaFolder string) chan uint32 { func (s *scanner) startProgressTracker(mediaFolder string) (chan uint32, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
progress := make(chan uint32, 100) progress := make(chan uint32, 100)
go func() { go func() {
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0}) s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0})
@ -135,25 +136,26 @@ func (s *scanner) startProgressTracker(mediaFolder string) chan uint32 {
}) })
}() }()
for { for {
count, more := <-progress select {
if !more { case <-ctx.Done():
break return
case count := <-progress:
if count == 0 {
continue
}
totalFolders, totalFiles := s.incStatusCounter(mediaFolder, count)
s.broker.SendMessage(&events.ScanStatus{
Scanning: true,
Count: int64(totalFiles),
FolderCount: int64(totalFolders),
})
} }
if count == 0 {
continue
}
totalFolders, totalFiles := s.incStatusCounter(mediaFolder, count)
s.broker.SendMessage(&events.ScanStatus{
Scanning: true,
Count: int64(totalFiles),
FolderCount: int64(totalFolders),
})
} }
}() }()
return progress return progress, cancel
} }
func (s *scanner) RescanAll(fullRescan bool) error { func (s *scanner) RescanAll(ctx context.Context, fullRescan bool) error {
if s.Scanning() { if s.Scanning() {
log.Debug("Scanner already running, ignoring request for rescan.") log.Debug("Scanner already running, ignoring request for rescan.")
return ErrAlreadyScanning return ErrAlreadyScanning
@ -164,7 +166,7 @@ func (s *scanner) RescanAll(fullRescan bool) error {
defer s.cacheWarmer.Flush(context.Background()) defer s.cacheWarmer.Flush(context.Background())
var hasError bool var hasError bool
for folder := range s.folders { for folder := range s.folders {
err := s.rescan(folder, fullRescan) err := s.rescan(ctx, folder, fullRescan)
hasError = hasError || err != nil hasError = hasError || err != nil
} }
if hasError { if hasError {
@ -232,8 +234,8 @@ func (s *scanner) Status(mediaFolder string) (*StatusInfo, error) {
}, nil }, nil
} }
func (s *scanner) getLastModifiedSince(folder string) time.Time { func (s *scanner) getLastModifiedSince(ctx context.Context, folder string) time.Time {
ms, err := s.ds.Property(context.TODO()).Get(model.PropLastScan + "-" + folder) ms, err := s.ds.Property(ctx).Get(model.PropLastScan + "-" + folder)
if err != nil { if err != nil {
return time.Time{} return time.Time{}
} }
@ -252,7 +254,8 @@ func (s *scanner) updateLastModifiedSince(folder string, t time.Time) {
} }
func (s *scanner) loadFolders() { func (s *scanner) loadFolders() {
fs, _ := s.ds.MediaFolder(context.TODO()).GetAll() ctx := context.TODO()
fs, _ := s.ds.MediaFolder(ctx).GetAll()
for _, f := range fs { for _, f := range fs {
log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path) log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
s.folders[f.Path] = s.newScanner(f) s.folders[f.Path] = s.newScanner(f)
@ -260,7 +263,7 @@ func (s *scanner) loadFolders() {
active: false, active: false,
fileCount: 0, fileCount: 0,
folderCount: 0, folderCount: 0,
lastUpdate: s.getLastModifiedSince(f.Path), lastUpdate: s.getLastModifiedSince(ctx, f.Path),
} }
} }
} }

View file

@ -39,7 +39,8 @@ func (c *LibraryScanningController) GetScanStatus(w http.ResponseWriter, r *http
} }
func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) { func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
loggedUser, ok := request.UserFrom(r.Context()) ctx := r.Context()
loggedUser, ok := request.UserFrom(ctx)
if !ok { if !ok {
return nil, newError(responses.ErrorGeneric, "Internal error") return nil, newError(responses.ErrorGeneric, "Internal error")
} }
@ -51,9 +52,9 @@ func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Req
fullScan := utils.ParamBool(r, "fullScan", false) fullScan := utils.ParamBool(r, "fullScan", false)
go func() { go func() {
err := c.scanner.RescanAll(fullScan) err := c.scanner.RescanAll(ctx, fullScan)
if err != nil { if err != nil {
log.Error(r.Context(), err) log.Error(ctx, err)
} }
}() }()