(ns metabase-enterprise.cache.strategies (:require [java-time.api :as t] [metabase.models.cache-config :as cache-config] [metabase.public-settings.premium-features :refer [defenterprise defenterprise-schema]] [metabase.query-processor.middleware.cache-backend.db :as backend.db] [metabase.util.cron :as u.cron] [metabase.util.log :as log] [metabase.util.malli.schema :as ms] [toucan2.core :as t2])) | |
(set! *warn-on-reflection* true) | |
Data shape | |
Schema for a caching strategy | (defenterprise CacheStrategy :feature :cache-granular-controls [] [:and [:map [:type [:enum :nocache :ttl :duration :schedule]]] [:multi {:dispatch :type} [:nocache [:map ;; not closed due to a way it's used in tests for clarity [:type [:= :nocache]]]] [:ttl [:map {:closed true} [:type [:= :ttl]] [:multiplier ms/PositiveInt] [:min_duration_ms ms/IntGreaterThanOrEqualToZero] ^:internal [:invalidated-at {:optional true} some?]]] [:duration [:map {:closed true} [:type [:= :duration]] [:duration ms/PositiveInt] [:unit [:enum "hours" "minutes" "seconds" "days"]] ^:internal [:invalidated-at {:optional true} some?]]] [:schedule [:map {:closed true} [:type [:= :schedule]] [:schedule u.cron/CronScheduleString] ^:internal [:invalidated-at {:optional true} some?]]]]]) |
Querying DB | |
(defenterprise-schema cache-strategy :- [:maybe (CacheStrategy)] "Returns the granular cache strategy for a card." :feature :cache-granular-controls [card dashboard-id] (let [qs (for [[i model model-id] [[1 "question" (:id card)] [2 "dashboard" dashboard-id] [3 "database" (:database_id card)] [4 "root" 0]] :when model-id] {:from [:cache_config] :select [:id [[:inline i] :ordering]] :where [:and [:= :model [:inline model]] [:= :model_id model-id]]}) q {:from [[{:union-all qs} :unused_alias]] :select [:id] :order-by :ordering :limit [:inline 1]} item (t2/select-one :model/CacheConfig :id q)] (cache-config/card-strategy item card))) | |
Strategy execution | |
Generate prepared statement for a db cache backend for a given strategy | (defmulti ^:private fetch-cache-stmt-ee* (fn [strategy _hash _conn] (:type strategy))) |
(defmethod fetch-cache-stmt-ee* :ttl [strategy query-hash conn] (backend.db/fetch-cache-stmt-ttl strategy query-hash conn)) | |
(defmethod fetch-cache-stmt-ee* :duration [strategy query-hash conn] (if-not (and (:duration strategy) (:unit strategy)) (log/debugf "Caching strategy %s should have :duration and :unit" (pr-str strategy)) (let [duration (t/duration (:duration strategy) (keyword (:unit strategy))) duration-ago (t/minus (t/offset-date-time) duration) invalidated-at (t/max duration-ago (:invalidated-at strategy))] (backend.db/prepare-statement conn query-hash invalidated-at)))) | |
(defmethod fetch-cache-stmt-ee* :schedule [{:keys [invalidated-at] :as strategy} query-hash conn] (if-not invalidated-at (log/debugf "Caching strategy %s has not run yet" (pr-str strategy)) (backend.db/prepare-statement conn query-hash invalidated-at))) | |
(defmethod fetch-cache-stmt-ee* :nocache [_ _ _] nil) | |
Returns prepared statement to query for db cache backend. | (defenterprise fetch-cache-stmt :feature :cache-granular-controls [strategy query-hash conn] (fetch-cache-stmt-ee* strategy query-hash conn)) |