2

我正在玩future并且似乎无法让它与javax.mail. 例如,为了好玩,我试图设置一个复合处理程序来抓取一堆电子邮件并将它们放入数据库中,但在所有电子邮件被收集和插入之前向客户提供响应。

println我在函数(下面)中有几个s import-posts,当我从 repl 运行它时,它工作正常,142 journal messages.第一次打印(因为 db 是空的),No new messages.第二次打印。当我通过运行本地开发码头服务器进行尝试时,每次加载页面时都会得到println输出,并且它们永远不会插入到数据库中。142 journal messages好的,然后我尝试将它们从 repl 导入到数据库中,然后从码头尝试,我仍然142 journal messages每次都得到。实现这一目标的最佳方法是什么?

复合处理程序:

(GET "/" request
     (if-let [usr_id (:id (friend/current-authentication))]
       (friend/authorize
         #{:pojagi.models.usr/user}

         ;; this is where I'm having trouble
         (do (future (let [folder (mail/get-folder mail/gmail "Inbox")]
                       (println "importing emails from " (.getName folder) ".")
                       (mail/import-posts usr_id folder)))
           (index/home)))


       (index/index (:flash request))))

导入邮件功能:

(defn import-posts
  [usr_id ^javax.mail.Folder folder & {:keys [subject-term public?]}]
  (let [messages (get-latest-messages usr_id folder)
        journals (into [] (.search folder (SubjectTerm. (or subject-term "journal")) messages))]
    (println (count journals) "journal messages.")
    (if (< (count journals) 2)
      (println "No new messages.")
      (map
        (fn [journal]
          (println "inserting journal" (.getSubject journal))
          (let [[title created bodyparts uid :as post] [(.getSubject journal)
                                                        (-> journal .getSentDate .getTime (java.sql.Timestamp.))
                                                        (-> journal .getContent)
                                                        (-> folder (.getUID journal))]
                body (-> (.getBodyPart bodyparts 0)
                       .getDataHandler .getInputStream slurp md/md-to-html-string)]
            (post/insert {:title title :body body :created created :usr_id 4 :public true :email_uid uid})
            ))
        journals) )))
4

2 回答 2

2

你可能被懒虫咬了:

如果你环绕doallmap可能会有所帮助

(doall (map
    (fn [journal]

或者dorun如果您不想在之后检查结果(dorun 就像 doall 不保存整个序列,所以不太可能耗尽内存)

(dorun (map
    (fn [journal]

当您从 repl 运行 import-posts 时,repl 会打印映射fn [journal]日志的结果,这会导致将它们插入数据库的副作用。当码头运行时,什么都不看结果,序列仍然是延迟未实现的,并且不会发生副作用。

于 2013-07-02T22:32:22.070 回答
1

在因为内存不足而尝试之后for,我终于发现doseq对于这种产生副作用的活动来说这是一个可行的选择,因为它不会尝试将整个集合保存在内存中:

(defn import-posts
  [usr_id ^javax.mail.Folder folder & {:keys [subject-term public?]}]
  (let [last-uid (post/last-uid usr_id)
        messages (get-latest-messages usr_id folder last-uid)
        journals (into [] (.search folder (SubjectTerm. (or subject-term "journal")) messages))]
    (if (and (< (count journals) 2)
             (= last-uid (-> folder (.getUID (first journals)))))
      (println "No new messages.")
      (doseq [import (map
                       (fn [journal]
                         (println "inserting journal" (.getSubject journal))
                         (let [[title created bodyparts uid :as post] [(.getSubject journal)
                                                                       (-> journal .getSentDate .getTime (java.sql.Timestamp.))
                                                                       (-> journal .getContent)
                                                                       (-> folder (.getUID journal))]
                               body (-> (.getBodyPart bodyparts 0)
                                      .getDataHandler .getInputStream slurp md/md-to-html-string)]
                           (post/insert {:title title :body body :created created :usr_id 4 :public true :email_uid uid})))
                       journals)]
        import))))
于 2013-07-03T00:05:10.430 回答