未来不能使用javax.mail

时间:2013-07-02 22:19:19

标签: multithreading clojure javamail future

我正在玩future并且似​​乎无法使用javax.mail。例如,为了好玩,我正在尝试设置一个compojure处理程序来抓取一堆电子邮件并将它们放入数据库中,但在收集和插入电子邮件之前向客户端发送响应。

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

compojure handler:

(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) )))

2 个答案:

答案 0 :(得分:2)

你可能被懒惰的小虫咬伤了:

如果您在doall周围包裹map可能有帮助

(doall (map
    (fn [journal]

dorun如果您不想在之后检查结果(dorun就像doall那样不能保存整个序列,因此不太可能耗尽内存)

(dorun (map
    (fn [journal]

当您从repl运行import-posts时,repl会打印将fn [journal]映射到日志上的结果,这会导致将它们插入数据库的副作用。 当jetty运行时,没有看到结果,序列仍然懒惰 - 未实现,副作用不会发生。

答案 1 :(得分: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))))