Files
soroush.asadi f0ce286527
Build backend images / build content-svc (push) Failing after 54s
Build backend images / build file-svc (push) Failing after 56s
Build backend images / build gateway (push) Failing after 57s
Build backend images / build identity-svc (push) Failing after 58s
Build backend images / build notification-svc (push) Failing after 1m4s
Build backend images / build render-svc (push) Failing after 2m27s
Build backend images / build studio-svc (push) Failing after 55s
fix(scan): force-kill stale AE processes before each launch (fresh start)
PrepareFreshAE = taskkill AfterFX/aerender/AfterFXLib/dynamiclinkmanager/QT32
+ 2s settle + clear crash markers, then launch. A hung/zombie AE from a prior
job would otherwise block or corrupt the new run. RunScan now calls it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 21:27:34 +03:30

61 lines
2.1 KiB
Go

package runner
import (
"os"
"os/exec"
"path/filepath"
"time"
)
// aeProcesses are the AE-related executables to force-kill before a fresh launch.
var aeProcesses = []string{
"AfterFX.exe", // the AE app
"aerender.exe", // the headless renderer
"AfterFXLib.exe", // AE render engine
"dynamiclinkmanager.exe", // Dynamic Link
"Adobe QT32 Server.exe", // QuickTime/media server
}
// PrepareFreshAE guarantees a clean AE start before a scan/render: it force-kills
// any leftover AE process (a hung/zombie instance from a prior job would otherwise
// block or corrupt the new launch), waits for them to release file locks, then
// clears the crash/Safe-Mode markers. Call this right before launching afterfx/aerender.
func PrepareFreshAE() {
if os.Getenv("APPDATA") == "" {
return // non-Windows / dev
}
KillAEProcesses()
time.Sleep(2 * time.Second) // let the OS reap processes + release locks
ClearAECrashState()
}
// KillAEProcesses force-terminates every AE-related process tree (taskkill is a
// Windows built-in — no external dep). Errors (e.g. "process not found") are ignored.
func KillAEProcesses() {
for _, name := range aeProcesses {
_ = exec.Command("taskkill", "/F", "/T", "/IM", name).Run()
}
}
// ClearAECrashState removes the markers After Effects uses to decide it crashed,
// so the blocking "Crash Repair Options" (Safe Mode) dialog never appears:
// 1. SCRPriorState.json in each AE prefs version dir (session crash-recovery state).
// 2. HKCU\Software\Adobe\After Effects\AppStates — a leftover per-session GUID
// (after a kill/crash) trips Safe Mode. reg.exe is a Windows built-in.
// Targeted (vs. wiping all prefs) so the node keeps its AE preferences.
func ClearAECrashState() {
appData := os.Getenv("APPDATA")
if appData == "" {
return
}
base := filepath.Join(appData, "Adobe", "After Effects")
if entries, err := os.ReadDir(base); err == nil {
for _, e := range entries {
if e.IsDir() {
_ = os.Remove(filepath.Join(base, e.Name(), "SCRPriorState.json"))
}
}
}
_ = exec.Command("reg", "delete", `HKCU\Software\Adobe\After Effects\AppStates`, "/f").Run()
}