Clojure并发:自动化SQL查询

Clojure并发:自动化SQL查询,sql,concurrency,clojure,functional-programming,Sql,Concurrency,Clojure,Functional Programming,我有一个小程序,可以逐个读取SQL查询/命令,并对数据库执行它们 如果查询成功执行,则执行下一个查询。 如果执行一个查询时出错,程序应该同时停止执行 我有代码,只是即使出现异常,查询仍会继续执行 (defn main [] (loop [queries (get-all-queries) querycount 1] (let [q (first queries)] (println (format "currently processin

我有一个小程序,可以逐个读取SQL查询/命令,并对数据库执行它们

如果查询成功执行,则执行下一个查询。 如果执行一个查询时出错,程序应该同时停止执行

我有代码,只是即使出现异常,查询仍会继续执行

(defn main
   []
   (loop [queries (get-all-queries)
          querycount 1]
     (let [q (first queries)]
        (println (format "currently processing query %s", querycount))
        (cond (nil? q) (println "All Queries ran successfully.")
              :else (do
                      (cond (= (:status (process-query q querycount)) "OK") 
                               (recur (rest queries) (+querycount 1)))
                      :else (println "An error occured while running queries")))))))


 (defn process-query
     [query query-count]
     (let [{query-body :query-body, is-query-running? :is-query-running?} query
           my-agent (agent 
                       {:error false, :query-count query-count} 
                       :error-handler handler-fn)]
        (send my-agent (fn[_]
                          (execute-query! db query-body)))))
        (loop [is-query-running? (is-query-running?)
               error? (:error @my-agent)]
           (cond error? (do (println "Error") 
                            {:status "ERROR" :error-msg (:error-msg @my-agent)})
           (and (not is-query-running?) (not error?)) (do (println "Success") 
                                                          {:status "OK"})
           (:else (do
                    (Thread/sleep 2000)
                    (recur (is-query-running?) (:error @my-agent)))))))


(defn handler-fn
  [agent exception]
  (println (format "an exception occured : %s" exception))
  (if (instance? java.sql.BatchUpdateException exception)
      (println (.getNextException exception)))
  (send agent (? [_] {:error true, :error-message exception}))
  (throw exception))
我使用代理的原因是,我有一些查询需要4小时才能运行。 当这种情况发生时,数据库不会通知程序查询已经完成。相反,程序被卡住了。因此,相反,我不断地轮询以检查查询是否已经完成

  • 这是完成我想做的事情的最好方法吗
  • 我应该使用其他并发原语吗
  • 我甚至需要并发原语吗
  • 我已经想了很久了

我认为您需要使用core.async来解决此类工作流 看看
此库允许您检查相关异步任务的条件

一些可能对您有帮助的资源


主要问题似乎是:一方面,您编写的长查询永远不会返回,即它们甚至不会抛出异常。另一方面,代理的错误检测机制基于捕获异常

(defn main
   []
   (loop [queries (get-all-queries)
          querycount 1]
     (let [q (first queries)]
        (println (format "currently processing query %s", querycount))
        (cond (nil? q) (println "All Queries ran successfully.")
              :else (do
                      (cond (= (:status (process-query q querycount)) "OK") 
                               (recur (rest queries) (+querycount 1)))
                      :else (println "An error occured while running queries")))))))


 (defn process-query
     [query query-count]
     (let [{query-body :query-body, is-query-running? :is-query-running?} query
           my-agent (agent 
                       {:error false, :query-count query-count} 
                       :error-handler handler-fn)]
        (send my-agent (fn[_]
                          (execute-query! db query-body)))))
        (loop [is-query-running? (is-query-running?)
               error? (:error @my-agent)]
           (cond error? (do (println "Error") 
                            {:status "ERROR" :error-msg (:error-msg @my-agent)})
           (and (not is-query-running?) (not error?)) (do (println "Success") 
                                                          {:status "OK"})
           (:else (do
                    (Thread/sleep 2000)
                    (recur (is-query-running?) (:error @my-agent)))))))


(defn handler-fn
  [agent exception]
  (println (format "an exception occured : %s" exception))
  (if (instance? java.sql.BatchUpdateException exception)
      (println (.getNextException exception)))
  (send agent (? [_] {:error true, :error-message exception}))
  (throw exception))
我认为您需要做的不是(主要)检查是否捕获了异常,而是检查
执行查询
在运行
查询时是否实际返回了有效结果?
返回false

关于正确的并发原语,我建议使用future而不是代理。它们比代理更简单,因为它们只能返回一个值,而不是多次更改其状态,并且它们的错误处理方式是简单地返回异常而不是常规返回值


然后,您可以遵循这个实现思想:在循环中,对未来的超时执行一个
deref
。如果
deref
的返回值是任何
执行查询定期返回,返回
“OK”
(分别在
未来
正文中添加第二个表达式,作为可明确识别的返回值,例如关键字
:OK
)。否则,如果
deref
的返回值是异常,则像现在一样从异常返回
“ERROR”
,并返回
:ERROR msg
。最后,如果返回值是您给
deref
的超时值,则调用
是否正在运行查询?
。如果为true,则循环另一次,如果为false,则返回
ERROR
,并带有一个特殊的
:ERROR msg
,它表明查询结束时既不返回也不引发异常。(并且可能会调用
future cancel
,这样就不会泄漏没完没了的
execute query!
调用的线程。)

查询是如何运行的?
工作原理。代码中不清楚这一点,因为它在每个查询映射中作为一个值传入,这可能是问题的关键,因为
进程查询
将返回
“OK”
,如果
查询正在运行?
在代理的
键变为true之前变为false:error
键。是否-query-running?运行查询并检索所有正在执行的查询,然后检查当前查询是否在运行的查询中。如果是,则返回true。如果返回的是
true
而不是其本身,则应在
recur
调用
过程查询中得到一条错误消息。Clojure是一个Lisp-1,因此返回值
true
会在
循环
中隐藏
是否正在运行查询?
的函数定义。Dude,请将源代码格式化为最多80列。@Igrapenthin,对不起,Dude。代码格式化。