재실행 시 영상 재처리로 인한 멈춤 완화 — ffmpeg/ffprobe 저우선순위 + 백업 하루 1회

증상: 영상이 많은 라이브러리에서 첫 로딩이 오래 걸리고, 다 불러온 뒤
재실행하면 멈춤. 원인은 미완료 영상 썸네일 백로그가 시작 시
enqueue_pending으로 재개되는데, ffmpeg/ffprobe가 '자식 프로세스'라
스레드 저우선순위(이전 수정)를 상속받지 못해 NORMAL로 전 코어를 포화시켜
WebView UI가 멈춘 것. (재실행 시 전체 재스캔은 없음 — 자동스캔은 dev 전용,
워처도 시작 시 스캔 안 함. 재처리는 미완료 썸네일 재개일 뿐.)

- ffmpeg::command(): Windows CREATE_NO_WINDOW에 BELOW_NORMAL_PRIORITY_CLASS 추가,
  Unix는 pre_exec로 setpriority(nice+10). 검증: 스캔 중 ffmpeg/ffprobe
  PriorityClass=BelowNormal 관측(ffmpeg 406, ffprobe 46 샘플).
- 시작 유지보수 스레드도 저우선순위로, DB 백업(VACUUM INTO=전체 복제)은
  24시간 내 백업 있으면 건너뜀 — 대용량 라이브러리 재실행 부하/디스크 낭비 감소.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
강 한
2026-07-19 20:05:41 +09:00
co-authored by Claude Fable 5
parent 8ba0c24ce8
commit 2bb1711ffa
2 changed files with 33 additions and 8 deletions
+22 -7
View File
@@ -81,16 +81,31 @@ fn which(name: &str) -> Option<PathBuf> {
None
}
/// 콘솔 창 없이 실행되는 Command 생성 (Windows CREATE_NO_WINDOW)
/// 콘솔 창 없이 + 저우선순위로 실행되는 Command 생성.
/// ffmpeg/ffprobe는 CPU 집약적이라 자식 프로세스를 저우선순위로 띄워야
/// (스레드 우선순위는 자식에 상속되지 않음) 영상 다수 처리 중에도 UI가 멈추지 않는다.
pub fn command(path: &Path) -> Command {
let cmd = Command::new(path);
let mut cmd = Command::new(path);
#[cfg(windows)]
let cmd = {
{
use std::os::windows::process::CommandExt;
let mut c = cmd;
c.creation_flags(0x0800_0000);
c
};
// CREATE_NO_WINDOW(0x0800_0000) | BELOW_NORMAL_PRIORITY_CLASS(0x0000_4000)
cmd.creation_flags(0x0800_0000 | 0x0000_4000);
}
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
// fork 후 exec 전에 자식 니스값을 올린다(우선순위 하향). setpriority(PRIO_PROCESS,self,10).
unsafe {
cmd.pre_exec(|| {
extern "C" {
fn setpriority(which: i32, who: u32, prio: i32) -> i32;
}
setpriority(0, 0, 10);
Ok(())
});
}
}
cmd
}
+11 -1
View File
@@ -187,8 +187,18 @@ fn main() {
std::thread::Builder::new()
.name("maintenance".into())
.spawn(move || {
// 유지보수는 백그라운드 — 시작 시 UI를 방해하지 않도록 저우선순위.
archive_indexer::prio::set_current_thread_low();
let backup = data_dir.join("archive.db.bak");
if let Err(e) = archive_indexer::maintenance::backup_db(&db, &backup) {
// 백업(VACUUM INTO = DB 전체 복제)은 하루 한 번만 — 대용량 라이브러리에서
// 매 실행 백업은 시작을 느리게 하고 디스크를 낭비한다.
let backup_fresh = std::fs::metadata(&backup)
.and_then(|m| m.modified())
.map(|t| t.elapsed().map(|e| e.as_secs() < 24 * 3600).unwrap_or(false))
.unwrap_or(false);
if backup_fresh {
tracing::debug!("최근(24h 내) 백업 존재 — 이번 실행은 백업 건너뜀");
} else if let Err(e) = archive_indexer::maintenance::backup_db(&db, &backup) {
tracing::warn!("DB 백업 실패: {e}");
}
let cutoff = now_ms() - 30 * 24 * 3600 * 1000;