mirror of
https://github.com/penpot/penpot.git
synced 2025-05-29 09:26:11 +02:00
♻️ Refactor exporter browser management.
Replace the cluster dependency with generic-pool.
This commit is contained in:
parent
18d9212253
commit
4c430cedf5
7 changed files with 197 additions and 175 deletions
|
@ -6,8 +6,10 @@
|
|||
|
||||
(ns app.browser
|
||||
(:require
|
||||
["puppeteer-cluster" :as ppc]
|
||||
["puppeteer-core" :as pp]
|
||||
["generic-pool" :as gp]
|
||||
[app.common.data :as d]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[lambdaisland.glogi :as log]
|
||||
[promesa.core :as p]))
|
||||
|
@ -20,12 +22,6 @@
|
|||
(str "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"))
|
||||
|
||||
(defn exec!
|
||||
[browser f]
|
||||
(.execute ^js browser (fn [props]
|
||||
(let [page (unchecked-get props "page")]
|
||||
(f page)))))
|
||||
|
||||
(defn set-cookie!
|
||||
[page {:keys [key value domain]}]
|
||||
(.setCookie ^js page #js {:name key
|
||||
|
@ -100,36 +96,76 @@
|
|||
|
||||
;; --- BROWSER STATE
|
||||
|
||||
(def instance (atom nil))
|
||||
(defonce pool (atom nil))
|
||||
(defonce pool-browser-id (atom 1))
|
||||
|
||||
(defn- create-browser
|
||||
[concurrency strategy]
|
||||
(let [strategy (case strategy
|
||||
:browser (.-CONCURRENCY_BROWSER ^js ppc/Cluster)
|
||||
:incognito (.-CONCURRENCY_CONTEXT ^js ppc/Cluster)
|
||||
:page (.-CONCURRENCY_PAGE ^js ppc/Cluster))
|
||||
opts #js {:concurrency strategy
|
||||
:maxConcurrency concurrency
|
||||
:puppeteerOptions #js {:args #js ["--no-sandbox"]}}]
|
||||
(.launch ^js ppc/Cluster opts)))
|
||||
(def browser-pool-factory
|
||||
(letfn [(create []
|
||||
(let [path (cf/get :browser-executable-path "/usr/bin/google-chrome")]
|
||||
(-> (pp/launch #js {:executablePath path :args #js ["--no-sandbox"]})
|
||||
(p/then (fn [browser]
|
||||
(let [id (deref pool-browser-id)]
|
||||
(log/info :origin "factory" :action "create" :browser-id id)
|
||||
(unchecked-set browser "__num_use" 0)
|
||||
(unchecked-set browser "__id" id)
|
||||
(swap! pool-browser-id inc)
|
||||
browser))))))
|
||||
(destroy [obj]
|
||||
(let [id (unchecked-get obj "__id")]
|
||||
(log/info :origin "factory" :action "destroy" :browser-id id)
|
||||
(.close ^js obj)))
|
||||
|
||||
(validate [obj]
|
||||
(let [max-use (cf/get :browser-max-usage 10)
|
||||
num-use (unchecked-get obj "__num_use")
|
||||
id (unchecked-get obj "__id")]
|
||||
|
||||
(log/info :origin "factory" :action "validate" :browser-id id :max-use max-use :num-use num-use :obj obj)
|
||||
(if (> num-use max-use)
|
||||
(p/resolved false)
|
||||
(do
|
||||
(unchecked-set obj "__num_use" (inc num-use))
|
||||
(p/resolved (.isConnected ^js obj))))))]
|
||||
|
||||
#js {:create create
|
||||
:destroy destroy
|
||||
:validate validate}))
|
||||
|
||||
(defn init
|
||||
[]
|
||||
(let [concurrency (cf/get :browser-concurrency)
|
||||
strategy (cf/get :browser-strategy)]
|
||||
(-> (create-browser concurrency strategy)
|
||||
(p/then #(reset! instance %))
|
||||
(p/catch (fn [error]
|
||||
(log/error :msg "failed to initialize browser")
|
||||
(js/console.error error))))))
|
||||
(log/info :msg "initializing browser pool")
|
||||
(let [opts #js {:max (cf/get :browser-pool-max 3)
|
||||
:min (cf/get :browser-pool-min 0)
|
||||
:testOnBorrow true
|
||||
:evictionRunIntervalMillis 30000
|
||||
:numTestsPerEvictionRun 5
|
||||
:acquireTimeoutMillis 120000 ; 2min
|
||||
:idleTimeoutMillis 30000}]
|
||||
|
||||
(reset! pool (gp/createPool browser-pool-factory opts))
|
||||
(p/resolved nil)))
|
||||
|
||||
(defn stop
|
||||
[]
|
||||
(if-let [instance @instance]
|
||||
(p/do!
|
||||
(.idle ^js instance)
|
||||
(.close ^js instance)
|
||||
(log/info :msg "shutdown headless browser"))
|
||||
(p/resolved nil)))
|
||||
(when-let [pool (deref pool)]
|
||||
(log/info :msg "finalizing browser pool")
|
||||
(-> (.drain ^js pool)
|
||||
(p/then (fn [] (.clear ^js pool))))))
|
||||
|
||||
(defn exec!
|
||||
[f]
|
||||
(letfn [(on-acquire [pool browser]
|
||||
(p/let [ctx (.createIncognitoBrowserContext ^js browser)
|
||||
page (.newPage ^js ctx)]
|
||||
(-> (p/do! (f page))
|
||||
(p/handle
|
||||
(fn [result error]
|
||||
(-> (p/do! (.close ^js ctx)
|
||||
(.release ^js pool browser))
|
||||
(p/handle (fn [_ _]
|
||||
(if result
|
||||
(p/resolved result)
|
||||
(p/rejected error))))))))))]
|
||||
(when-let [pool (deref pool)]
|
||||
(-> (.acquire ^js pool)
|
||||
(p/then (partial on-acquire pool))))))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
:value token}))
|
||||
|
||||
(defn screenshot-object
|
||||
[browser {:keys [file-id page-id object-id token scale type]}]
|
||||
[{:keys [file-id page-id object-id token scale type]}]
|
||||
(letfn [(handle [page]
|
||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (u/uri (cf/get :public-uri))
|
||||
|
@ -55,7 +55,7 @@
|
|||
:png (bw/screenshot dom {:omit-background? true :type type})
|
||||
:jpeg (bw/screenshot dom {:omit-background? false :type type}))))))]
|
||||
|
||||
(bw/exec! browser handle)))
|
||||
(bw/exec! handle)))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -74,22 +74,16 @@
|
|||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(let [browser @bw/instance]
|
||||
(when-not browser
|
||||
(ex/raise :type :internal
|
||||
:code :browser-not-ready
|
||||
:hint "browser cluster is not initialized yet"))
|
||||
|
||||
(p/let [content (screenshot-object browser params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
(case (:type params)
|
||||
:png ".png"
|
||||
:jpeg ".jpg")))
|
||||
:length (alength content)
|
||||
:mime-type (case (:type params)
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg")})))
|
||||
(p/let [content (screenshot-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
(case (:type params)
|
||||
:png ".png"
|
||||
:jpeg ".jpg")))
|
||||
:length (alength content)
|
||||
:mime-type (case (:type params)
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg")}))
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
:value token}))
|
||||
|
||||
(defn pdf-from-object
|
||||
[browser {:keys [file-id page-id object-id token scale type]}]
|
||||
[{:keys [file-id page-id object-id token scale type]}]
|
||||
(letfn [(handle [page]
|
||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (u/uri (cf/get :public-uri))
|
||||
|
@ -44,7 +44,7 @@
|
|||
(bw/wait-for page "#screenshot")
|
||||
(bw/pdf page))))]
|
||||
|
||||
(bw/exec! browser handle)))
|
||||
(bw/exec! handle)))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -62,18 +62,12 @@
|
|||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(let [browser @bw/instance]
|
||||
(when-not browser
|
||||
(ex/raise :type :internal
|
||||
:code :browser-not-ready
|
||||
:hint "browser cluster is not initialized yet"))
|
||||
|
||||
(p/let [content (pdf-from-object browser params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".pdf"))
|
||||
:length (alength content)
|
||||
:mime-type "application/pdf"})))
|
||||
(p/let [content (pdf-from-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".pdf"))
|
||||
:length (alength content)
|
||||
:mime-type "application/pdf"}))
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
|
||||
|
||||
(defn- render-object
|
||||
[browser {:keys [page-id file-id object-id token scale suffix type]}]
|
||||
[{:keys [page-id file-id object-id token scale suffix type]}]
|
||||
(letfn [(convert-to-ppm [pngpath]
|
||||
(log/trace :fn :convert-to-ppm)
|
||||
(let [basepath (path/dirname pngpath)
|
||||
|
@ -279,7 +279,7 @@
|
|||
rctx {:cookie cookie
|
||||
:uri (str uri)}]
|
||||
(log/info :uri (:uri rctx))
|
||||
(bw/exec! browser (partial handle rctx)))))
|
||||
(bw/exec! (partial handle rctx)))))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -298,18 +298,11 @@
|
|||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(let [browser @bw/instance]
|
||||
(when-not browser
|
||||
(ex/raise :type :internal
|
||||
:code :browser-not-ready
|
||||
:hint "browser cluster is not initialized yet"))
|
||||
|
||||
|
||||
(p/let [content (render-object browser params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".svg"))
|
||||
:length (alength content)
|
||||
:mime-type "image/svg+xml"})))
|
||||
(p/let [content (render-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".svg"))
|
||||
:length (alength content)
|
||||
:mime-type "image/svg+xml"}))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue