1

我有一种情况,我观察一个特定目录以进行文件系统更改。如果该目录中的某个文件被更改,我会重新读取它,附加一些现有的缓存信息,并将其存储在atom.

相关代码看起来像

(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-watching 库)中的错误。

有什么想法可以解决它或进一步诊断它吗?

4

1 回答 1

1

:callback挂起是由作为to传递的函数内部引发的错误引起的watch/start

在这种情况下,根本原因是修改后的文件正在被复制到服务器scp(这不是原子的,因此第一个事件在复制完成之前触发,这就是导致抛出 JSON 解析错误的原因)。

如果抛出任何类型的错误watch/start,它会静默失败,这会加剧这种情况。:callback

这里的解决方案是

  1. 用于rsync复制文件。它会自动复制,但不会:modify在目标文件上生成任何事件,只会在相关的临时文件上生成。由于其原子副本的工作方式,它只会发出:create事件信号。

  2. 将/包裹:callback在其中,并让子句返回原子的旧值。这将导致运行多次,但最后一次将是文件复制完成,这最终应该做正确的事情。trycatchcatchload-posts!

(我都做过,但两者都可以实际解决问题)。

第三种选择是使用报告错误的 FS-watching 库,例如Hawkdirwatch(或者可能是hara.io.watch?我没有使用任何这些,所以我无法评论)。

诊断这涉及:callback用包裹身体

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

看看实际抛出了什么。一旦打印出 JSON 解析错误,就很容易获得关于出了什么问题的理论。

于 2016-09-08T19:12:41.370 回答