Allow serialization errors through internal error handling.

This commit is contained in:
Alexander K. Hudek 2014-12-02 13:14:18 -05:00
parent e67aa2508a
commit d88471409e
3 changed files with 22 additions and 10 deletions

View file

@ -1,4 +1,4 @@
(defproject views "0.4.3"
(defproject views "0.4.4"
:description "You underestimate the power of the SQL side"
:url "https://github.com/diligenceengine/views"

View file

@ -1,4 +1,5 @@
(ns views.db.deltas
(:import (java.sql SQLException))
(:require
[clojure.string :refer [split]]
[clojure.java.jdbc :as j]
@ -8,7 +9,7 @@
[views.db.load :as vdbl]
[views.db.checks :as vc]
[views.db.honeysql :as vh]
[views.db.util :refer [safe-map log-exception]]))
[views.db.util :refer [safe-map log-exception serialization-error?]]))
;;
;; Terminology and data structures used throughout this code
@ -218,9 +219,10 @@
(try
(let [refresh-set (get (vdbl/initial-view db view-sig templates view) view-sig)]
(update-in d [view-sig] (update-deltas-with-refresh-set refresh-set)))
(catch Exception e ;; ignore any failed view deltas
(log-exception e)
d)))
;; allow serialization errors
(catch SQLException e (if (serialization-error? e) (throw e) d))
;; ignore any failed view deltas
(catch Exception e (log-exception e) d)))
deltas
refresh-only-views))

View file

@ -9,7 +9,7 @@
;; java.sql.SQLException: ERROR: could not serialize access due to concurrent update
;;
(defn get-nested-exceptions*
[exceptions e]
[exceptions ^SQLException e]
(if-let [next-e (.getNextException e)]
(recur (conj exceptions next-e) next-e)
exceptions))
@ -19,6 +19,11 @@
[e]
(get-nested-exceptions* [e] e))
(defn serialization-error?
"True if e is a serialization error."
[^SQLException e]
(boolean (some #(= (.getSQLState ^SQLException %) "40001") (get-nested-exceptions e))))
;; TODO: update to avoid stack overflow.
(defn retry-on-transaction-failure
"Retry a function whenever we receive a transaction failure."
@ -31,7 +36,7 @@
(debug "Exception message: " (.getMessage e))
;; (debug "stack trace message: " (.printStackTrace e))
(if (some #(= (.getSQLState %) "40001") (get-nested-exceptions e))
(if (serialization-error? e)
(retry-on-transaction-failure transaction-fn) ;; try it again
(throw e))))) ;; otherwise rethrow
@ -42,7 +47,7 @@
(retry-on-transaction-failure tfn#)))
(defn log-exception
[e]
[^Exception e]
(error "views internal"
(str
"e: " e
@ -50,6 +55,11 @@
" trace: " (with-out-str (print-stack-trace e)))))
(defn safe-map
"A non-lazy map that skips any results that throw exeptions."
"A non-lazy map that skips any results that throw exeptions other than SQL
serialization errors."
[f items]
(reduce #(try (conj %1 (f %2)) (catch Exception e %1)) [] items))
(reduce #(try (conj %1 (f %2))
(catch SQLException e (if (serialization-error? e) (throw e) %1))
(catch Exception e %1))
[]
items))