Rust와 notify-rs를 이용한 파일 감시 — 동기화 앱을 위한 핫 폴더

발행: (2026년 5월 14일 PM 12:13 GMT+9)
3 분 소요
원문: Dev.to

Source: Dev.to

기본 설정

[dependencies]
notify = "6"
use notify::{RecommendedWatcher, RecursiveMode, Watcher, Config};
use std::sync::mpsc;

fn watch_directory(path: &str) -> Result {
    let (tx, rx) = mpsc::channel();

    let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
    watcher.watch(path.as_ref(), RecursiveMode::Recursive)?;

    for res in rx {
        match res {
            Ok(event) => handle_event(event),
            Err(e) => log::error!("Watch error: {:?}", e),
        }
    }
    Ok(())
}

RecommendedWatcher는 macOS에서 FSEvents(네이티브 파일 시스템 이벤트 API)를 사용합니다. 오버헤드가 낮고 알림이 빠릅니다.

이중 트리거 문제

파일 저장 작업은 종종 여러 이벤트를 발생시킵니다(Modify, Modify, Create, Modify 등). 일반적으로 네 번이 아니라 한 번의 동기화 트리거만 원합니다.

디바운스

use std::time::{Duration, Instant};
use std::collections::HashMap;
use std::path::PathBuf;

struct Debouncer {
    last_seen: HashMap,
    delay: Duration,
}

impl Debouncer {
    fn should_process(&mut self, path: &PathBuf) -> bool {
        let now = Instant::now();
        let last = self
            .last_seen
            .entry(path.clone())
            .or_insert(Instant::now() - self.delay * 2);

        if now.duration_since(*last) >= self.delay {
            *last = now;
            true
        } else {
            false
        }
    }
}

300–500 ms 정도의 디바운스 윈도우면 대부분의 편집기 저장 동작을 커버하면서도 느리게 느껴지지 않습니다.

감시할 대상 필터링

모든 파일 변경이 동기화를 일으켜서는 안 됩니다. 예시 필터:

fn should_ignore(path: &Path) -> bool {
    let name = path
        .file_name()
        .and_then(|n| n.to_str())
        .unwrap_or("");

    // 숨김 파일
    name.starts_with('.')
    // 임시 파일
    || name.ends_with(".tmp")
    || name.ends_with('~')
    // macOS 메타데이터
    || name == ".DS_Store"
    // 이미 동기화 중인 파일
    || name.ends_with(".sync")
}

Tauri에서 워처 실행하기

워처는 백그라운드 스레드에서 실행되어야 Tokio 런타임을 차단하지 않습니다:

std::thread::spawn(move || {
    if let Err(e) = watch_directory(&path) {
        log::error!("Watcher failed: {:?}", e);
    }
});

채널이나 앱 핸들의 emit 시스템을 통해 Tauri와 통신합니다.

결론

macOS에서 FSEvents를 사용하는 notify‑rs는 견고합니다. 이중 트리거 문제는 디바운스로 해결해야 하며, 처음부터 구현하는 것이 좋습니다. 관련 없는 변경에 반응하지 않도록 필터를 적극적으로 적용하세요.

이 글이 도움이 되었다면 ❤️ 하나가 생각보다 큰 힘이 됩니다 — 감사합니다!

Hiyoko PDF Vault
X

0 조회
Back to Blog

관련 글

더 보기 »