future not working with javax.mail

风流意气都作罢 提交于 2020-01-04 13:40:52

问题


I'm playing with future and and can't seem to get it to work with javax.mail. For example, for fun, I'm trying to set up a compojure handler to grab a bunch of emails and put them into a database, but deliver a response to the client before the emails have all been gathered and inserted.

I have a few printlns going on in the import-posts function (below), and when I run this from the repl, it works fine, printing 142 journal messages. the first time (because the db is empty), and No new messages. the second time. When I try it by running the local development jetty server, I get a println output of 142 journal messages every time I load the page, and they never get inserted into the db. Okay, so then I tried to import them into the db from the repl and then try it from jetty, and I still got 142 journal messages every time. What's the best way to accomplish this?

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

function for importing emails:

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

回答1:


you may have been bitten by the lazy-bug:

if you wrap a doall around the map it may help

(doall (map
    (fn [journal]

or dorun if you don't want to check the result after (dorun is like doall that does not hold the entire sequence, so less likely to run out of memory)

(dorun (map
    (fn [journal]

When you run import-posts from the repl, the repl prints the result of mapping the fn [journal] over the journals, which causes the side effect of inserting them into the database. When jetty runs this nothing looks at the result, the sequence remains lazily-unrealized, and the side effects to not take place.




回答2:


After also attempting for because I was running out of memory, I finally figured out that doseq is a workable choice for this kind of side-effect producing activity, because it won't try to hold the entire collection in memory:

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


来源:https://stackoverflow.com/questions/17436762/future-not-working-with-javax-mail

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!