2016-09-08 3 views
1

У меня есть situation, где я просматриваю конкретный каталог для изменения файловой системы. Если какой-либо файл в этом каталоге изменен, я перечитаю его, прикрепите некоторую существующую кешированную информацию и сохраните ее в atom.Обновление Atom зависает во время вызова вызова Clojure

Соответствующий код выглядит

(def posts (atom [])) 

(defn load-posts! [] 
    (swap! 
    posts 
    (fn [old] 
    (vec 
     (map #(let [raw (json/parse-string % (fn [k] (keyword (.toLowerCase k))))] 
       (<snip some processing of raw, including getting some pieces from old>)) 
      (line-seq (io/reader "watched.json"))))))) 


;; elsewhere, inside of -main 
(watch/start-watch 
    [{:path "resources/" 
     :event-types [:modify] 
     :callback (fn [event filename] 
        (when (and (= :modify event) (= "watched.json" filename)) 
        (println "Reloading posts.json ...") 
        (posts/load-posts!)))} 
    ...]) 

Это заканчивается прекрасно работать локально, но когда я развернуть его на свой сервер, swap! вызова висит примерно на полпути через.

Я попытался ее отладки через println, который сказал мне

  1. Файловая система, триггер является увольняют.
  2. swap! не работает функция больше, чем когда-то
  3. отслеживаемых файл открывается и анализируется
  4. Некоторые записи из файла обрабатываются, но обработка прекращается при поступлении 111 (который, кажется, не будет значительно отличается от любых предыдущих записей).
  5. Обновление не завершено, поэтому сохранено старое значение этого atom
  6. Никаких событий файловой системы не запускается после этого.

Я подозреваю, что это проблема памяти или где-то ошибка в Clojure-Watch (или в базовой библиотеке просмотра FS).

Любые идеи, как я могу это исправить или диагностировать дальше?

+3

Похоже, что во время обработки происходит проглатывание. Поверните встроенную функцию, отображаемую в строке-seq, в отдельные отдельные функции и проверьте их на соответствующей записи. –

+1

... или попробуйте/поймайте вызов «load-posts!» И посмотрите, что его выбрасывает. – Alex

ответ

1

Повреждение вызвано ошибкой, возникающей внутри функции, переданной как :callback, до watch/start.

Основная причина в этом случае заключается в том, что модифицированный файл копируется на сервер scp (который не является атомарным, и поэтому первое событие запускается до завершения копирования, что является причиной того, что ошибка синтаксического анализа JSON быть брошенным).

Это усугубляется тем фактом, что watch/start терпит неудачу, если его :callback вызывает любую ошибку.

Решения здесь

  1. Использование rsync для копирования файлов. Он копирует атомарно , но не генерирует никаких :modify событий в целевом файле, только связанные временные файлы. Из-за того, как работает его атомная копия, будет только сигнал :create события.

  2. Оберните :callback в try/catch, и есть пункт catch вернуть старое значение атома. Это приведет к тому, что load-posts! будет выполняться несколько раз, но в последний раз будет завершено копирование файла, что должно, в конечном итоге, сделать правильно.

(Я сделал то и другое, но либо реалистично решил бы проблему).

Третий вариант использует FS-просмотре библиотеки, сообщать об ошибках, таких как Hawk или dirwatch (или, возможно, hara.io.watch? Я не использовал ни одного из них, так что я не могу комментировать).

Диагностировать это участие обертывания :callback тела

(try 
    <body> 
    (catch Exception e 
    (println "ERROR IN SWAP!" e) 
    old)) 

, чтобы увидеть, что на самом деле бросает. Как только это напечатало ошибку анализа JSON, было довольно легко получить теорию о том, что происходит не так.

+1

Пара комментариев к ответу-scp не пытается быть атомарным, но rsync делает. См. Http://rsync.samba.org/how-rsync-works.html и http://stackoverflow.com/questions/3769263/are-rsync-operations-atomic-at-file-level#6903839. Таким образом, можно часто наблюдать за событием «создать», которое запускается, когда rsync выполняет mv временного direntry на постоянный. –

+0

Функция start-watch возвращает будущее, но оно не было разыменовано. Есть два других активных проекта: ястреб и dirwatch; оба из них выглядят как .printStackTrace вместо исключений. –

+0

@JonahB - Я начал с 'rsync', но переключился на' scp', потому что я не видел с ним событий ': modify'. Я буду проверять, будет ли получен событие ': create', и обновить мой ответ, если это произойдет (этот способ требует гораздо меньшего взлома). – Inaimathi