mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 16:31:39 +02:00
♻️ Refactor internal backend error handling
This commit is contained in:
parent
3ceb4cf895
commit
57c83b5d53
1 changed files with 80 additions and 56 deletions
|
@ -40,41 +40,43 @@
|
||||||
:version/frontend (or (yrq/get-header request "x-frontend-version") "unknown")
|
:version/frontend (or (yrq/get-header request "x-frontend-version") "unknown")
|
||||||
:version/backend (:full cf/version)}))
|
:version/backend (:full cf/version)}))
|
||||||
|
|
||||||
(defmulti handle-exception
|
(defmulti handle-error
|
||||||
(fn [err & _rest]
|
(fn [cause _ _]
|
||||||
(let [edata (ex-data err)]
|
(-> cause ex-data :type)))
|
||||||
(or (:type edata)
|
|
||||||
(class err)))))
|
|
||||||
|
|
||||||
(defmethod handle-exception :authentication
|
(defmulti handle-exception
|
||||||
[err _]
|
(fn [cause _ _]
|
||||||
|
(class cause)))
|
||||||
|
|
||||||
|
(defmethod handle-error :authentication
|
||||||
|
[err _ _]
|
||||||
{::yrs/status 401
|
{::yrs/status 401
|
||||||
::yrs/body (ex-data err)})
|
::yrs/body (ex-data err)})
|
||||||
|
|
||||||
(defmethod handle-exception :authorization
|
(defmethod handle-error :authorization
|
||||||
[err _]
|
[err _ _]
|
||||||
{::yrs/status 403
|
{::yrs/status 403
|
||||||
::yrs/body (ex-data err)})
|
::yrs/body (ex-data err)})
|
||||||
|
|
||||||
(defmethod handle-exception :restriction
|
(defmethod handle-error :restriction
|
||||||
[err _]
|
[err _ _]
|
||||||
{::yrs/status 400
|
{::yrs/status 400
|
||||||
::yrs/body (ex-data err)})
|
::yrs/body (ex-data err)})
|
||||||
|
|
||||||
(defmethod handle-exception :rate-limit
|
(defmethod handle-error :rate-limit
|
||||||
[err _]
|
[err _ _]
|
||||||
(let [headers (-> err ex-data ::http/headers)]
|
(let [headers (-> err ex-data ::http/headers)]
|
||||||
{::yrs/status 429
|
{::yrs/status 429
|
||||||
::yrs/headers headers}))
|
::yrs/headers headers}))
|
||||||
|
|
||||||
(defmethod handle-exception :concurrency-limit
|
(defmethod handle-error :concurrency-limit
|
||||||
[err _]
|
[err _ _]
|
||||||
(let [headers (-> err ex-data ::http/headers)]
|
(let [headers (-> err ex-data ::http/headers)]
|
||||||
{::yrs/status 429
|
{::yrs/status 429
|
||||||
::yrs/headers headers}))
|
::yrs/headers headers}))
|
||||||
|
|
||||||
(defmethod handle-exception :validation
|
(defmethod handle-error :validation
|
||||||
[err request]
|
[err request parent-cause]
|
||||||
(let [{:keys [code] :as data} (ex-data err)]
|
(let [{:keys [code] :as data} (ex-data err)]
|
||||||
(cond
|
(cond
|
||||||
(= code :spec-validation)
|
(= code :spec-validation)
|
||||||
|
@ -97,21 +99,23 @@
|
||||||
|
|
||||||
(= code :invalid-image)
|
(= code :invalid-image)
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(l/error :hint "unexpected error on processing image" :cause err)
|
(let [cause (or parent-cause err)]
|
||||||
{::yrs/status 400 ::yrs/body data})
|
(l/error :hint "unexpected error on processing image" :cause cause)
|
||||||
|
{::yrs/status 400 ::yrs/body data}))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
{::yrs/status 400 ::yrs/body data})))
|
{::yrs/status 400 ::yrs/body data})))
|
||||||
|
|
||||||
(defmethod handle-exception :assertion
|
(defmethod handle-error :assertion
|
||||||
[error request]
|
[error request parent-cause]
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(let [{:keys [code] :as data} (ex-data error)]
|
(let [{:keys [code] :as data} (ex-data error)
|
||||||
|
cause (or parent-cause error)]
|
||||||
(cond
|
(cond
|
||||||
(= code :data-validation)
|
(= code :data-validation)
|
||||||
(let [explain (::sm/explain data)
|
(let [explain (::sm/explain data)
|
||||||
payload (sm/humanize-data explain)]
|
payload (sm/humanize-data explain)]
|
||||||
(l/error :hint "Data assertion error" :message (ex-message error) :cause error)
|
(l/error :hint "data assertion error" :message (ex-message error) :cause cause)
|
||||||
{::yrs/status 500
|
{::yrs/status 500
|
||||||
::yrs/body {:type :server-error
|
::yrs/body {:type :server-error
|
||||||
:code :assertion
|
:code :assertion
|
||||||
|
@ -121,7 +125,7 @@
|
||||||
|
|
||||||
(= code :spec-validation)
|
(= code :spec-validation)
|
||||||
(let [explain (ex/explain data)]
|
(let [explain (ex/explain data)]
|
||||||
(l/error :hint "Spec assertion error" :message (ex-message error) :cause error)
|
(l/error :hint "spec assertion error" :message (ex-message error) :cause cause)
|
||||||
{::yrs/status 500
|
{::yrs/status 500
|
||||||
::yrs/body {:type :server-error
|
::yrs/body {:type :server-error
|
||||||
:code :assertion
|
:code :assertion
|
||||||
|
@ -131,33 +135,48 @@
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
(l/error :hint "Assertion error" :message (ex-message error) :cause error)
|
(l/error :hint "assertion error" :message (ex-message error) :cause cause)
|
||||||
{::yrs/status 500
|
{::yrs/status 500
|
||||||
::yrs/body {:type :server-error
|
::yrs/body {:type :server-error
|
||||||
:code :assertion
|
:code :assertion
|
||||||
:data data}})))))
|
:data data}})))))
|
||||||
|
|
||||||
|
(defmethod handle-error :not-found
|
||||||
(defmethod handle-exception :not-found
|
[err _ _]
|
||||||
[err _]
|
|
||||||
{::yrs/status 404
|
{::yrs/status 404
|
||||||
::yrs/body (ex-data err)})
|
::yrs/body (ex-data err)})
|
||||||
|
|
||||||
(defmethod handle-exception :internal
|
(defmethod handle-error :internal
|
||||||
[error request]
|
[error request parent-cause]
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(l/error :hint "Internal error" :message (ex-message error) :cause error)
|
(let [cause (or parent-cause error)]
|
||||||
{::yrs/status 500
|
(l/error :hint "internal error" :message (ex-message error) :cause cause)
|
||||||
::yrs/body {:type :server-error
|
{::yrs/status 500
|
||||||
:code :unhandled
|
::yrs/body {:type :server-error
|
||||||
:hint (ex-message error)
|
:code :unhandled
|
||||||
:data (ex-data error)}}))
|
:hint (ex-message error)
|
||||||
|
:data (ex-data error)}})))
|
||||||
|
|
||||||
|
(defmethod handle-error :default
|
||||||
|
[error request parent-cause]
|
||||||
|
(let [edata (ex-data error)]
|
||||||
|
;; This is a special case for the idle-in-transaction error;
|
||||||
|
;; when it happens, the connection is automatically closed and
|
||||||
|
;; next-jdbc combines the two errors in a single ex-info. We
|
||||||
|
;; only need the :handling error, because the :rollback error
|
||||||
|
;; will be always "connection closed".
|
||||||
|
(if (and (ex/exception? (:rollback edata))
|
||||||
|
(ex/exception? (:handling edata)))
|
||||||
|
(handle-exception (:handling edata) request error)
|
||||||
|
(handle-exception error request parent-cause))))
|
||||||
|
|
||||||
(defmethod handle-exception org.postgresql.util.PSQLException
|
(defmethod handle-exception org.postgresql.util.PSQLException
|
||||||
[error request]
|
[error request parent-cause]
|
||||||
(let [state (.getSQLState ^java.sql.SQLException error)]
|
(let [state (.getSQLState ^java.sql.SQLException error)
|
||||||
|
cause (or parent-cause error)]
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(l/error :hint "PSQL error" :message (ex-message error) :cause error)
|
(l/error :hint "PSQL error" :message (ex-message error)
|
||||||
|
:cause cause)
|
||||||
(cond
|
(cond
|
||||||
(= state "57014")
|
(= state "57014")
|
||||||
{::yrs/status 504
|
{::yrs/status 504
|
||||||
|
@ -179,39 +198,44 @@
|
||||||
:state state}}))))
|
:state state}}))))
|
||||||
|
|
||||||
(defmethod handle-exception :default
|
(defmethod handle-exception :default
|
||||||
[error request]
|
[error request parent-cause]
|
||||||
(let [edata (ex-data error)]
|
(let [edata (ex-data error)
|
||||||
|
cause (or parent-cause error)]
|
||||||
(cond
|
(cond
|
||||||
;; This means that exception is not a controlled exception.
|
;; This means that exception is not a controlled exception.
|
||||||
(nil? edata)
|
(nil? edata)
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(l/error :hint "Unexpected error" :message (ex-message error) :cause error)
|
(l/error :hint "unexpected error" :message (ex-message error) :cause cause)
|
||||||
{::yrs/status 500
|
{::yrs/status 500
|
||||||
::yrs/body {:type :server-error
|
::yrs/body {:type :server-error
|
||||||
:code :unexpected
|
:code :unexpected
|
||||||
:hint (ex-message error)}})
|
:hint (ex-message error)}})
|
||||||
|
|
||||||
;; This is a special case for the idle-in-transaction error;
|
|
||||||
;; when it happens, the connection is automatically closed and
|
|
||||||
;; next-jdbc combines the two errors in a single ex-info. We
|
|
||||||
;; only need the :handling error, because the :rollback error
|
|
||||||
;; will be always "connection closed".
|
|
||||||
(and (ex/exception? (:rollback edata))
|
|
||||||
(ex/exception? (:handling edata)))
|
|
||||||
(handle-exception (:handling edata) request)
|
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(binding [l/*context* (request->context request)]
|
(binding [l/*context* (request->context request)]
|
||||||
(l/error :hint "Unhandled error" :message (ex-message error) :cause error)
|
(l/error :hint "unhandled error" :message (ex-message error) :cause cause)
|
||||||
{::yrs/status 500
|
{::yrs/status 500
|
||||||
::yrs/body {:type :server-error
|
::yrs/body {:type :server-error
|
||||||
:code :unhandled
|
:code :unhandled
|
||||||
:hint (ex-message error)
|
:hint (ex-message error)
|
||||||
:data edata}}))))
|
:data edata}}))))
|
||||||
|
|
||||||
|
(defmethod handle-exception java.util.concurrent.CompletionException
|
||||||
|
[cause request _]
|
||||||
|
(let [cause' (ex-cause cause)]
|
||||||
|
(if (ex/error? cause)
|
||||||
|
(handle-error cause' request cause)
|
||||||
|
(handle-exception cause' request cause))))
|
||||||
|
|
||||||
|
(defmethod handle-exception java.util.concurrent.ExecutionException
|
||||||
|
[cause request _]
|
||||||
|
(let [cause' (ex-cause cause)]
|
||||||
|
(if (ex/error? cause')
|
||||||
|
(handle-error cause' request cause)
|
||||||
|
(handle-exception cause' request cause))))
|
||||||
|
|
||||||
(defn handle
|
(defn handle
|
||||||
[cause request]
|
[cause request]
|
||||||
(if (or (instance? java.util.concurrent.CompletionException cause)
|
(if (ex/error? cause)
|
||||||
(instance? java.util.concurrent.ExecutionException cause))
|
(handle-error cause request nil)
|
||||||
(handle-exception (ex-cause cause) request)
|
(handle-exception cause request nil)))
|
||||||
(handle-exception cause request)))
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue