Merge pull request #7680 from penpot/niwinz-staging-file-export-fix
Some checks failed
Commit Message Check / Check Commit Message (push) Has been cancelled

🐛 Fix race condition on file export process
This commit is contained in:
Alejandro Alonso
2025-11-05 07:45:26 +01:00
committed by GitHub
6 changed files with 31 additions and 28 deletions

View File

@@ -28,8 +28,8 @@
com.google.guava/guava {:mvn/version "33.4.8-jre"} com.google.guava/guava {:mvn/version "33.4.8-jre"}
funcool/yetti funcool/yetti
{:git/tag "v11.6" {:git/tag "v11.8"
:git/sha "94dc017" :git/sha "1d1b33f"
:git/url "https://github.com/funcool/yetti.git" :git/url "https://github.com/funcool/yetti.git"
:exclusions [org.slf4j/slf4j-api]} :exclusions [org.slf4j/slf4j-api]}

View File

@@ -550,7 +550,7 @@
[cfg data file-id] [cfg data file-id]
(let [library-ids (get-libraries cfg [file-id])] (let [library-ids (get-libraries cfg [file-id])]
(reduce (fn [data library-id] (reduce (fn [data library-id]
(if-let [library (get-file cfg library-id)] (if-let [library (get-file cfg library-id :include-deleted? true)]
(ctf/absorb-assets data (:data library)) (ctf/absorb-assets data (:data library))
data)) data))
data data

View File

@@ -228,6 +228,7 @@
(db/tx-run! cfg (fn [cfg] (db/tx-run! cfg (fn [cfg]
(cond-> (bfc/get-file cfg file-id (cond-> (bfc/get-file cfg file-id
{:realize? true {:realize? true
:include-deleted? true
:lock-for-update? true}) :lock-for-update? true})
detach? detach?
(-> (ctf/detach-external-references file-id) (-> (ctf/detach-external-references file-id)
@@ -285,13 +286,11 @@
(let [file (cond-> (select-keys file bfc/file-attrs) (let [file (cond-> (select-keys file bfc/file-attrs)
(:options data) (:options data)
(assoc :options (:options data)) (assoc :options (:options data)))
:always file (-> file
(dissoc :data)) (dissoc :data)
(dissoc :deleted-at)
file (cond-> file
:always
(encode-file)) (encode-file))
path (str "files/" file-id ".json")] path (str "files/" file-id ".json")]

View File

@@ -64,9 +64,13 @@
(let [mdata (meta result) (let [mdata (meta result)
response (if (fn? result) response (if (fn? result)
(result request) (result request)
(let [result (rph/unwrap result)] (let [result (rph/unwrap result)
{::yres/status (::http/status mdata 200) status (::http/status mdata 200)
::yres/headers (::http/headers mdata {}) headers (cond-> (::http/headers mdata {})
(yres/stream-body? result)
(assoc "content-type" "application/octet-stream"))]
{::yres/status status
::yres/headers headers
::yres/body result}))] ::yres/body result}))]
(-> response (-> response
(handle-response-transformation request mdata) (handle-response-transformation request mdata)

View File

@@ -25,10 +25,10 @@
[app.rpc.commands.projects :as projects] [app.rpc.commands.projects :as projects]
[app.rpc.commands.teams :as teams] [app.rpc.commands.teams :as teams]
[app.rpc.doc :as-alias doc] [app.rpc.doc :as-alias doc]
[app.rpc.helpers :as rph]
[app.tasks.file-gc] [app.tasks.file-gc]
[app.util.services :as sv] [app.util.services :as sv]
[app.worker :as-alias wrk] [app.worker :as-alias wrk]))
[yetti.response :as yres]))
(set! *warn-on-reflection* true) (set! *warn-on-reflection* true)
@@ -44,7 +44,7 @@
(defn stream-export-v1 (defn stream-export-v1
[cfg {:keys [file-id include-libraries embed-assets] :as params}] [cfg {:keys [file-id include-libraries embed-assets] :as params}]
(yres/stream-body (rph/stream
(fn [_ output-stream] (fn [_ output-stream]
(try (try
(-> cfg (-> cfg
@@ -59,7 +59,7 @@
(defn stream-export-v3 (defn stream-export-v3
[cfg {:keys [file-id include-libraries embed-assets] :as params}] [cfg {:keys [file-id include-libraries embed-assets] :as params}]
(yres/stream-body (rph/stream
(fn [_ output-stream] (fn [_ output-stream]
(try (try
(-> cfg (-> cfg
@@ -79,16 +79,11 @@
::sm/params schema:export-binfile} ::sm/params schema:export-binfile}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id version file-id] :as params}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id version file-id] :as params}]
(files/check-read-permissions! pool profile-id file-id) (files/check-read-permissions! pool profile-id file-id)
(fn [_] (let [version (or version 1)]
(let [version (or version 1) (case (int version)
body (case (int version)
1 (stream-export-v1 cfg params) 1 (stream-export-v1 cfg params)
2 (throw (ex-info "not-implemented" {})) 2 (throw (ex-info "not-implemented" {}))
3 (stream-export-v3 cfg params))] 3 (stream-export-v3 cfg params))))
{::yres/status 200
::yres/headers {"content-type" "application/octet-stream"}
::yres/body body})))
;; --- Command: import-binfile ;; --- Command: import-binfile

View File

@@ -11,7 +11,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.http :as-alias http] [app.http :as-alias http]
[app.rpc :as-alias rpc] [app.rpc :as-alias rpc]
[yetti.response :as-alias yres])) [yetti.response :as yres]))
;; A utilty wrapper object for wrap service responses that does not ;; A utilty wrapper object for wrap service responses that does not
;; implements the IObj interface that make possible attach metadata to ;; implements the IObj interface that make possible attach metadata to
@@ -78,3 +78,8 @@
(let [exp (if (integer? max-age) max-age (inst-ms max-age)) (let [exp (if (integer? max-age) max-age (inst-ms max-age))
val (dm/fmt "max-age=%" (int (/ exp 1000.0)))] val (dm/fmt "max-age=%" (int (/ exp 1000.0)))]
(update response ::yres/headers assoc "cache-control" val))))) (update response ::yres/headers assoc "cache-control" val)))))
(defn stream
"A convenience allias for yetti.response/stream-body"
[f]
(yres/stream-body f))