fix(scan): Fix-mode scanner + dialog suppression + cancel/timer + importer revive
Build backend images / build content-svc (push) Failing after 1m25s
Build backend images / build file-svc (push) Failing after 1m10s
Build backend images / build gateway (push) Failing after 56s
Build backend images / build identity-svc (push) Failing after 53s
Build backend images / build notification-svc (push) Failing after 57s
Build backend images / build render-svc (push) Failing after 48s
Build backend images / build studio-svc (push) Failing after 1m5s

- scan.jsx: app.beginSuppressDialogs() + clean quit (no AE hang on font/footage
  dialogs); FIX-mode branch parses frl_c(x)t/m(y) layer names → scenes by c(x);
  flexible/mockup keep comp-based walk; FR_SCAN_MODE selects.
- render-svc: scan job carries project mode; cancel endpoint + node watchdog that
  kills AE on cancel; parseObjectURL handles minio:// (bucket in host); scan with
  no template fails cleanly; status guards so late results can't un-cancel.
- content importer: revive soft-deleted scenes instead of duplicate-inserting
  (fixes scenes_project_id_key unique violation); orphan diff ignores deleted.
- admin: scan dialog gets project-type picker + elapsed timer + Cancel button.
- node-agent: AE-2026 wiring (host port 5010, host-reachable presign endpoint),
  FR_SCAN_MODE plumbing. docs/aep-template-convention.md: per-type naming + bundles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-04 19:06:08 +03:30
parent ee670552a8
commit 6661f53734
17 changed files with 498 additions and 45 deletions
+30 -2
View File
@@ -31,6 +31,7 @@ import (
"path/filepath"
"runtime"
"sync"
"sync/atomic"
"syscall"
"time"
@@ -255,8 +256,35 @@ func (a *Agent) pollScanOnce(ctx context.Context) {
outPath := filepath.Join(a.cfg.WorkDir, "scans", claim.ScanJobID, "scan.json")
scanCtx, cancel2 := context.WithTimeout(ctx, 10*time.Minute)
result, serr := runner.RunScan(scanCtx, a.cfg.AfterFxPath, aepPath, a.cfg.WorkDir, outPath)
cancel2()
defer cancel2()
// Watchdog: if the user cancels the scan server-side, cancel the context →
// exec.CommandContext kills the AfterFX process.
var cancelled atomic.Bool
go func() {
t := time.NewTicker(3 * time.Second)
defer t.Stop()
for {
select {
case <-scanCtx.Done():
return
case <-t.C:
st, e := a.orch.ScanStatus(scanCtx, claim.ScanJobID)
if e == nil && (st == "cancelled" || st == "error") {
log.Printf("[scan %s] cancelled server-side — killing AE", claim.ScanJobID)
cancelled.Store(true)
cancel2()
return
}
}
}
}()
result, serr := runner.RunScan(scanCtx, a.cfg.AfterFxPath, aepPath, a.cfg.WorkDir, outPath, claim.Mode)
if cancelled.Load() {
log.Printf("[scan %s] aborted (cancelled)", claim.ScanJobID)
return // already cancelled in DB; don't report fail
}
if serr != nil {
a.failScan(claim.ScanJobID, serr.Error())
return