(ns metabase-enterprise.cache.strategies (:require [java-time.api :as t] [metabase.api.cache] [metabase.models.cache-config :as cache-config] [metabase.premium-features.core :refer [defenterprise defenterprise-schema]] [metabase.query-processor.middleware.cache-backend.db :as backend.db] [metabase.util.log :as log] [metabase.util.malli.registry :as mr] [toucan2.core :as t2])) | |
(set! *warn-on-reflection* true) | |
(comment metabase.api.cache/keep-me) | |
Data shape | |
(mr/def ::cache-strategy
"Schema for a caching strategy used internally"
[:and
:metabase.api.cache/cache-strategy.base
[:multi {:dispatch :type}
[:nocache :metabase.api.cache/cache-strategy.nocache]
[:ttl [:merge
:metabase.api.cache/cache-strategy.ttl
[:map
[:invalidated-at {:optional true} some?]]]]
[:duration [:merge
:metabase.api.cache/cache-strategy.ee.duration
[:map
[:invalidated-at {:optional true} some?]]]]
[:schedule [:merge
:metabase.api.cache/cache-strategy.ee.schedule
[:map
[:invalidated-at {:optional true} some?]]]]]]) | |
Querying DB | |
(defenterprise-schema cache-strategy :- [:maybe ::cache-strategy]
"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*
{:arglists '([strategy query-hash conn])}
(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)) |