SQLクエリ/コマンドを1つずつ読み取り、データベースに対して実行する小さなプログラムがあります。
クエリが正常に実行されると、次のクエリが実行されます。1 つのクエリの実行中にエラーが発生した場合、プログラムはすべて一緒に実行を停止する必要があります。
例外が発生した場合でもクエリが引き続き実行されることを除いて、コードがあります。
(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 時間かかるクエリがあるためです。その場合、データベースはクエリが完了したことをプログラムに通知しません。代わりに、プログラムが動かなくなります。そのため、代わりに、クエリが既に実行されているかどうかを確認するために常にポーリングしています。
- これは私がやろうとしていることを達成するための最良の方法ですか?
- 他の同時実行プリミティブを使用する必要がありますか?
- 同時実行プリミティブも必要ですか?
- 私はこれについて長い間考えてきました。