feat(scanner): quiet scans, enqueue coalescing, watcher probe, sibling cache
Part 2 of the faceted plan, Phase 5 (steps 5-6): the scan that used to print ~4 lines per unchanged file now prints ONE summary line, and a poll tick landing mid-scan no longer stacks a second full scan. - Quiet scans (§4): the walk loop is silent — inserts, changes, and errors log inside processMediaFile; the duplicate 'Successfully processed' branch (both branches printed it) and the per-file 'processing / already exists / same size, skipping' chatter are gone. Summary carries the trigger and a changed counter: 'Scan of <folders> (trigger: poll): N files, N changed, N new, Xs, N errors'. Triggers threaded through every enqueue site: poll (startBackupScan), watcher (dirty-dirs flush), admin (scan API), initial (startup scan). - Enqueue coalescing (§5): Worker.HasActiveScanForLibrary (JobResult gains additive job_type so only SCAN jobs coalesce — an import sharing the library id never blocks one). enqueueLibraryScan skips silently; the admin scan API answers 409 with the active job id. Enforces the one-scan-per-library invariant the bulk scan-state map leans on. - Watcher capability probe (§4): ONE Add on a root folder; failure disables the watcher with a single startup line (replaces the per-directory warning spam on inotify-broken deployments). The watcher stays an optional latency reducer over scheduled scans. - Per-directory sibling cache (§6): hasSiblingBookFileCached caches the ReadDir per directory for one scan — loose-image manga re-stats thousands of images sharing a handful of directories. Tests: TestHasActiveScanForLibrary (unit — running/pending coalesce, terminal jobs don't, non-scan jobs don't, empty library never, nil worker safe). Full scanner suite green in the container.
This commit is contained in:
1 parent
6750e9e0dc
commit
5245f292ca
5 files changed
+225
-49
No files matched your search
@@ -84,6 +84,23 @@ func (h *Handler) ScanLibrary(c *echo.Context) error {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "either library_id or folder_paths required for scanning"})
|
||||
}
|
||||
|
||||
// Coalescing (plan Part 2 §5): a scan for this library is already
|
||||
// pending or running — 409 with the active job so the UI can show
|
||||
// progress instead of stacking a second full scan.
|
||||
if req.LibraryID != "" && h.worker.HasActiveScanForLibrary(req.LibraryID) {
|
||||
var activeJobID string
|
||||
for _, active := range h.worker.GetActiveScanJobs() {
|
||||
if active.JobType == services.JobTypeScan && active.LibraryID == req.LibraryID {
|
||||
activeJobID = active.JobID
|
||||
break
|
||||
}
|
||||
}
|
||||
return c.JSON(http.StatusConflict, map[string]string{
|
||||
"error": "a scan for this library is already pending or running",
|
||||
"active_job_id": activeJobID,
|
||||
})
|
||||
}
|
||||
|
||||
jobID := uuid.New().String()
|
||||
|
||||
job := &services.Job{
|
||||
@@ -96,6 +113,7 @@ func (h *Handler) ScanLibrary(c *echo.Context) error {
|
||||
"admin_id": userUUID.String(),
|
||||
"db": h.db,
|
||||
"force": req.Force,
|
||||
"trigger": "admin",
|
||||
},
|
||||
Status: services.JobStatusPending,
|
||||
Context: h.ctx,
|
||||
|
||||
Reference in new issue
Block a user