【问题标题】:async clojure http-kit client with callback writing to database sqlite3带有回调写入数据库 sqlite3 的异步 clojure http-kit 客户端
【发布时间】:2017-03-01 08:40:33
【问题描述】:

在写入 sqlite 表时,我被 http-kit 异步行为所困扰。

数据库的 i/o 取决于我是将代码发送到 boot repl 还是将其作为 boot 脚本运行。 i/o 仅在 repl 情况下进行。我错过了什么?这是我的代码:

#!/usr/bin/env boot                                                                                                                                             

(defn deps [new-deps]                                                                                                                                           
  (boot.core/merge-env! :dependencies new-deps))                                                                                                                

(deps '[                                                                                                                                                        
        [http-kit  "2.2.0"]                                                                                                         
        [org.clojure/core.async  "0.2.395"]                                                                                                                     
        [org.clojure/java.jdbc  "0.7.0-alpha1"]                                                                                                                 
        [org.xerial/sqlite-jdbc  "3.16.1"]                                                                                                                      
        [org.slf4j/slf4j-nop "1.7.22"]                                                                                                                          
        ])                                                                                                                                                      

(require                                                                                                                                                        
         '[org.httpkit.client :as http]                                                                                                                         
         '[clojure.java.jdbc :as jdbc]                                                                                                                          
         )                                                                                                                                                      


(def db-spec                                                                                                                                                    
  {:classname "org.sqlite.JDBC"                                                                                                                                 
   :subprotocol "sqlite"                                                                                                                                        
   :subname "sqlite.db"})                                                                                                                                       

;(jdbc/db-do-commands                                                                                                                                           
  ;db-spec                                                                                                                                                      
  ;(jdbc/create-table-ddl "test" [[:msg :text]]))                                                                                                               

(def ins! (partial jdbc/insert! db-spec "test"))                                                                                                                

(http/get "http://locahost" {} (fn [_] (ins! {:msg "repl"})))                                                                                                   


(defn -main []                                                                                                                                                  
  (println (System/getProperty  "user.dir"))                                                                                                                    
  (http/get "http://locahost" {} (fn [_] (ins! {:msg "exec"}))))                                                                                                

谢谢

【问题讨论】:

  • 能否解决您的问题,因为它不起作用?它有一些问题:它缺少 clojure.java.jdbc 依赖项并指定 web 依赖项,这在您的问题中不是必需的,并且在公共 maven 存储库中不可用。

标签: asynchronous clojure sqlite callback http-kit


【解决方案1】:

脚本无法从命令行运行的问题是 http-kit 异步回调由 daemon threads 处理,唯一的非守护线程是运行脚本的主线程。

当您的-main 函数在向 http-kit 提交 HTTP 请求以进行异步处理后结束时,主线程终止并导致 JVM 在处理您的异步回调的守护线程有机会运行之前关闭。

您可以通过在-main 函数的末尾添加一个睡眠表达式来检查您的回调是否已执行:

(defn -main []                                                                                                                                                  
  (println (System/getProperty  "user.dir"))                                                                                                                    
  (http/get "http://locahost" {} (fn [_] (ins! {:msg "exec"})))
  (Thread/sleep 60000))

确保-main 函数等待处理结果的最佳方法是保持http/get 调用返回的承诺。承诺最终将包含您的回调函数产生的结果:

(let [result-promise (http/get "https://www.google.com" {} (fn [_] "Result"))]
  @result-promise)

@result-promise(deref result-promise) 的阅读器宏/快捷方式。

当您不想无限期阻塞时,完整的形式可能会更好 - 只需使用 timeout-ms 和 timeout-value 参数调用 deref

(deref result-promise 5000 "Didn't get response in 5 seconds. Giving up")

【讨论】:

  • 有没有比使用睡眠更简洁的方法来处理这个问题?
  • 我已更新我的答案以提供推荐的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 2017-12-15
  • 2017-08-30
  • 1970-01-01
相关资源
最近更新 更多