Util to put data into a temporary file and schedule it for deletion after a specified time period. Currently used to store card's rows data when sending notification since it can be large and we don't want to keep it in memory. | (ns metabase.notification.payload.temp-storage (:require [clojure.java.io :as io] [metabase.util.random :as random] [taoensso.nippy :as nippy]) (:import (java.io File) (java.util.concurrent Executors ScheduledThreadPoolExecutor))) |
(set! *warn-on-reflection* true) | |
(def ^:private temp-dir (delay (let [dir (io/file (System/getProperty "java.io.tmpdir") (str "metabase-notification-" (random/random-name)))] (.mkdirs dir) (.deleteOnExit dir) dir))) | |
(def ^:private deletion-scheduler (delay (Executors/newScheduledThreadPool 1))) | |
(defn- temp-file [] (doto (File/createTempFile "notification-" ".npy" @temp-dir) (.deleteOnExit))) | |
(defn- write-to-file [^File file data] (nippy/freeze-to-file file data)) | |
(defn- read-from-file [^File file] (when (.exists file) (nippy/thaw-from-file file))) | |
(.addShutdownHook (Runtime/getRuntime) (Thread. ^Runnable (fn [] (when @deletion-scheduler (.shutdown ^ScheduledThreadPoolExecutor @deletion-scheduler))))) | |
(defprotocol Cleanable (cleanup! [this] "Cleanup any resources associated with this object")) | |
(deftype TempFileStorage [^File file] Cleanable (cleanup! [_] (when (.exists file) (io/delete-file file true))) clojure.lang.IDeref (deref [_] (if (.exists file) (read-from-file file) (throw (ex-info "File no longer exists" {:file file})))) Object (toString [_] (str "#TempFileStorage{:file " file "}")) ;; Add equality behavior (equals [_this other] (and (instance? TempFileStorage other) (= file (.file ^TempFileStorage other)))) (hashCode [_] (.hashCode file))) | |
------------------------------------------------------------------------------------------------;; Public APIs ;; ------------------------------------------------------------------------------------------------;; | |
Write data to a temporary file. Returns a TempFileStorage type that: - Implements IDeref - use @ to read the data from the file - Implements Cleanable - call cleanup! when the file is no longer needed | (defn to-temp-file! [data] (let [f (temp-file)] (write-to-file f data) (TempFileStorage. f))) |