0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-08 16:00:19 -05:00

Improve retry mechanism and macros

This commit is contained in:
Andrey Antukh 2023-03-18 18:44:31 +01:00
parent 44a3f651c2
commit 4e7f32aa88
6 changed files with 50 additions and 45 deletions

View file

@ -361,12 +361,20 @@
[data]
(org.postgresql.util.PGInterval. ^String data))
(defn connection?
[conn]
(instance? Connection conn))
(defn savepoint
([^Connection conn]
(.setSavepoint conn))
([^Connection conn label]
(.setSavepoint conn (name label))))
(defn release!
[^Connection conn ^Savepoint sp ]
(.releaseSavepoint conn sp))
(defn rollback!
([^Connection conn]
(.rollback conn))

View file

@ -23,8 +23,8 @@
[app.loggers.webhooks :as-alias webhooks]
[app.main :as-alias main]
[app.rpc :as-alias rpc]
[app.rpc.retry :as rtry]
[app.tokens :as tokens]
[app.util.retry :as rtry]
[app.util.services :as-alias sv]
[app.util.time :as dt]
[app.worker :as wrk]
@ -203,7 +203,8 @@
;; this case we just retry the operation.
(rtry/with-retry {::rtry/when rtry/conflict-exception?
::rtry/max-retries 6
::rtry/label "persist-audit-log"}
::rtry/label "persist-audit-log"
::db/conn (dm/check db/connection? conn-or-pool)}
(let [now (dt/now)]
(db/insert! conn-or-pool :audit-log
(-> params

View file

@ -19,8 +19,8 @@
[app.rpc.commands.teams :as teams]
[app.rpc.doc :as-alias doc]
[app.rpc.quotes :as quotes]
[app.rpc.retry :as rtry]
[app.util.pointer-map :as pmap]
[app.util.retry :as rtry]
[app.util.services :as sv]
[app.util.time :as dt]
[clojure.spec.alpha :as s]))
@ -309,7 +309,8 @@
(rtry/with-retry {::rtry/when rtry/conflict-exception?
::rtry/max-retries 3
::rtry/label "create-comment-thread"}
::rtry/label "create-comment-thread"
::db/conn conn}
(create-comment-thread conn
{:created-at request-at
:profile-id profile-id

View file

@ -5,19 +5,20 @@
;; Copyright (c) KALEIDOS INC
(ns app.rpc.retry
"A fault tolerance RPC middleware. Allow retry some operations that we
know we can retry."
(:require
[app.common.logging :as l]
[app.util.retry :refer [conflict-exception?]]
[app.util.services :as sv]))
[app.db :as db]
[app.util.services :as sv])
(:import
org.postgresql.util.PSQLException))
(defn conflict-db-insert?
(defn conflict-exception?
"Check if exception matches a insertion conflict on postgresql."
[e]
(conflict-exception? e))
(and (instance? PSQLException e)
(= "23505" (.getSQLState ^PSQLException e))))
(def always-false (constantly false))
(def ^:private always-false (constantly false))
(defn wrap-retry
[_ f {:keys [::matches ::sv/name] :or {matches always-false} :as mdata}]
@ -40,3 +41,23 @@
(throw cause))))) 1))
f))
(defmacro with-retry
[{:keys [::when ::max-retries ::label ::db/conn] :or {max-retries 3}} & body]
`(let [conn# ~conn]
(assert (or (nil? conn#) (db/connection? conn#)) "invalid database connection")
(loop [tnum# 1]
(let [result# (let [sp# (some-> conn# db/savepoint)]
(try
(let [result# (do ~@body)]
(some->> sp# (db/release! conn#))
result#)
(catch Throwable cause#
(some->> sp# (db/rollback! conn#))
(if (and (~when cause#) (<= tnum# ~max-retries))
::retry
(throw cause#)))))]
(if (= ::retry result#)
(do
(l/warn :hint "retrying operation" :label ~label :retry tnum#)
(recur (inc tnum#)))
result#)))))

View file

@ -1,34 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.util.retry
"A fault tolerance helpers. Allow retry some operations that we know
we can retry."
(:require
[app.common.logging :as l])
(:import
org.postgresql.util.PSQLException))
(defn conflict-exception?
"Check if exception matches a insertion conflict on postgresql."
[e]
(and (instance? PSQLException e)
(= "23505" (.getSQLState ^PSQLException e))))
(defmacro with-retry
[{:keys [::when ::max-retries ::label] :or {max-retries 3}} & body]
`(loop [tnum# 1]
(let [result# (try
~@body
(catch Throwable cause#
(if (and (~when cause#) (<= tnum# ~max-retries))
::retry
(throw cause#))))]
(if (= ::retry result#)
(do
(l/warn :hint "retrying operation" :label ~label :retry tnum#)
(recur (inc tnum#)))
result#))))

View file

@ -108,6 +108,14 @@
`(do ~@body)
(reverse (partition 2 bindings))))
(defmacro check
"Applies a predicate to the value, if result is true, return the
value if not, returns nil."
[pred-fn value]
`(if (~pred-fn ~value)
~value
nil))
(defmacro get-prop
"A macro based, optimized variant of `get` that access the property
directly on CLJS, on CLJ works as get."