Fork me on GitHub

I have a database connection object which I’m using as a component, which I can then pass as an argument to database functions, e.g. (db/create conn-component my-thing). This works well.
The problem I’m running into is that whenever the connection is interrupted (database unreachable, network problem, etc.), using a database function will result in an exception. In this situation, the old database connection object becomes useless and I need a new one. How can I use component to solve or avoid this problem?


don't use a database connection as a component


use a connection pool or something you can get a connection from


What you can do is implement a defrecord that participates in the pseudo-protocol that expects from its db-conn argument


(defrecord DatabasePool [db datasource]
  (start [this]
    (log/info :msg "Starting database pool")
    (let [{:keys [dbtype host port dbname user password]} db]
      (when-not (= "postgresql" dbtype)
        (throw (ex-info "Unsupported dbtype" {:db db
                                              :dbtype dbtype})))
      (let [options (assoc default-database-pool-options
                           :server-name host
                           :port-number port
                           :database-name dbname
                           :username user
                           :password password)]
          (let [datasource (with-retries* #(hikari/make-datasource options))]
            (assoc this :datasource datasource))
          (catch Exception e
            (log/error :msg "Error creating database pool"
                       :exception e)
            (throw (ex-info "Invalid database pool" {:db db} e)))))))
  (stop [this]
    (log/info :msg "Stopping database pool")
    (when datasource
      (hikari/close-datasource datasource))
    (assoc this :datasource nil)))


the thing to do, independent of component, is use a connection pool