Проблемы с подключением к postgresql DB на Heroku с Korma (Clojure)
Я анализирую postgresql uri в настройках конфигурации на Heroku. Но я не могу заставить его работать. Любая помощь будет принята с благодарностью, я, вероятно, что-то упускаю прямо.
Вот код, используемый.
(def dev-db-info
{:db "dbname"
:user "username"})
(defn parse-db-uri
[uri]
(drop 1 (split uri #"://|:|@|/")))
(defn create-map-from-uri
[uri]
(let [parsed (parse-db-uri uri)]
(zipmap [:user :password :host :port :db] parsed)))
(defn db-info
[]
(if production?
(create-map-from-uri (System/getenv "DATABASE_URL"))
dev-db-info))
(defdb connected-db
(postgres (db-info)))
Карта, которую я извлекаю из Ури, выглядит так:
{:db "dbname"
:port "5662"
:host "ec2-url.compute-1.amazonaws.com"
:password "pwd"
:user "username"}
Я получаю следующую ошибку:
Connections could not be acquired from the underlying database!
РЕДАКТИРОВАТЬ:
С тех пор я отказался от использования Korma и переключился на использование Clojure.JDBC 0.2.3, который поддерживает "connection-uri" и, следовательно, ssl-соединения с БД. Корма в настоящее время не поддерживает это. Я опубликую проблему на Github, чтобы разрешить этот метод подключения.
4 ответа
РЕДАКТИРОВАТЬ: нет никаких оснований для использования [org.clojars.ccfontes/korma "0.3.0-beta12-pgssl"]
больше. Прочитайте это, чтобы узнать больше об этом. Также, пожалуйста, игнорируйте следующие инструкции.
Добавлена поддержка Postgres SSL.
В project.clj
вставить:[org.clojars.ccfontes/korma "0.3.0-beta12-pgssl"]
Определение подключения к базе данных postgres на heroku:
(ns app.db
(:require [clojure.java.jdbc :as sql]
[korma.db :as db]
[clojure.string :as string])
(:import (java.net URI)))
(defn set-app-pg-db! [mode]
(let [db-uri (java.net.URI. (System/getenv "DATABASE_URL"))]
(->> (string/split (.getUserInfo db-uri) #":")
(#(identity {:db (last (string/split (System/getenv "DATABASE_URL") #"\/"))
:host (.getHost db-uri)
:port (.getPort db-uri)
:user (% 0)
:password (% 1)
:ssl true
:sslfactory (when (= mode :dev) "org.postgresql.ssl.NonValidatingFactory")}))
(db/postgres)
(db/defdb app-pg-db))))
В исправлении используется пул соединений Tomcat JDBC и их пример конфигурации для пула соединений, поэтому он может не подходить для всех, кроме того, это всего лишь взлом. В идеале оригинальный проект Korma должен включать эти изменения или другое возможное решение.
Был бы признателен за отзывы от других людей, так как это было проверено только в моем собственном проекте. Благодарю.
В вашей EDIT вы упоминаете о переключении на clojure.java.jdbc, потому что это позволило вам включить SSL с использованием URI соединения. Вы можете использовать ту же технику с Korma, используя функцию korma.db/defdb, которая позволяет вам указать собственный URL-адрес подключения и включить SSL, используя строку запроса, например:
(defdb korma-db {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname "//localhost:5432/test?ssl=true"
:user "my-username"
:password "my-password"})
На самом деле решение действительно простое и работает только локально:
(defn- convert-db-uri [db-uri]
(let [[_ user password host port db] (re-matches #"postgres://(?:(.+):(.*)@)?([^:]+)(?::(\d+))?/(.+)" db-uri)]
{
:user user
:password password
:host host
:port (or port 80)
:db db
}))
(def db-spec (postgres
(convert-db-uri
(config/get "DATABASE_URL"))))
Где DATABASE_URL - это "postgres:// пользователь:pw@host:port/dbname? Ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory"
Кажется, имя БД пересылает параметры SSL в базовый драйвер, и это просто работает.
Это с:
[korma "0.3.0-beta9"]
[org.clojure/java.jdbc "0.1.3"]
[postgresql/postgresql "9.1-901.jdbc4"]
FWIW, вот код, который я использовал, чтобы получить clojure.java.jdbc db-spec (который, я думаю, и есть то, что хочет Korma) от Heroku DATABASE_URL
,
(def db-uri (java.net.URI. (System/getenv "DATABASE_URL")))
(def user-and-password (clojure.string/split (.getUserInfo db-uri) #":"))
(def db
{:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:user (get user-and-password 0)
:password (get user-and-password 1) ; may be nil
:subname (if (= -1 (.getPort db-uri))
(format "//%s%s" (.getHost db-uri) (.getPath db-uri))
(format "//%s:%s%s" (.getHost db-uri) (.getPort db-uri) (.getPath db-uri)))})