как я могу это сделать?
Я думал, что я могу что-то прочитать из базы данных, но это выглядит слишком много, есть что-то вроде?:
settings.DATABASES['default'].check_connection()
как я могу это сделать?
Я думал, что я могу что-то прочитать из базы данных, но это выглядит слишком много, есть что-то вроде?:
settings.DATABASES['default'].check_connection()
Все, что вам нужно сделать, это запустить приложение, и если он не подключен, он не будет работать. Другой способ, который вы можете попробовать, - включить оболочку из командной строки -
from django.db import connections
from django.db.utils import OperationalError
db_conn = connections['default']
try:
c = db_conn.cursor()
except OperationalError:
connected = False
else:
connected = True
Я использую следующую команду управления Django под названием wait_for_db
:
import time
from django.db import connection
from django.db.utils import OperationalError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""Django command that waits for database to be available"""
def handle(self, *args, **options):
"""Handle the command"""
self.stdout.write('Waiting for database...')
db_conn = None
while not db_conn:
try:
connection.ensure_connection()
db_conn = True
except OperationalError:
self.stdout.write('Database unavailable, waiting 1 second...')
time.sleep(1)
self.stdout.write(self.style.SUCCESS('Database available!'))
Предполагая, что вам это нужно из-за докера, НО не ограничивается докером, помните, что это в конце дня Bash и, таким образом, работает везде * NIX.
Сначала вам нужно будет использовать django-environ
, поскольку это значительно облегчит эту задачу.
Переменная окружения DATABASE_URL
будет использоваться внутри вашего приложения Django и здесь. Ваши настройки будут выглядеть так:
import environ
env = environ.Env()
...
DATABASES = {
'default': env.db('DATABASE_URL'),
'other': env.db('DATABASE_OTHER_URL') # for illustration purposes
}
...
Переменные вашей среды должны выглядеть примерно так: (подробнее здесь)
# This works with ALL the databases django supports ie (mysql/mssql/sqlite/...)
DATABASE_URL=postgres://user:[email protected]_of_box:5432/database_name
DATABASE_OTHER_URL=oracle://user:[email protected]/(description=(address=(host=name_of_box)(protocol=tcp)(port=1521))(connect_data=(SERVICE_NAME=EX)))
Внутри вашего entrypoint.sh
сделайте что-то вроде этого:
function database_ready() {
# You need to pass a single argument called "evironment_dsn"
python << EOF
import sys
import environ
from django.db.utils import ConnectionHandler, OperationalError
env = environ.Env()
try:
ConnectionHandler(databases={'default': env.db('$1')})['default'].ensure_connection()
except (OperationalError, DatabaseError):
sys.exit(-1)
sys.exit(0)
EOF
}
Затем, допустим, вы хотите дождаться своей основной database_ready
[в данном случае postgres], вы добавляете ее в тот же entrypoint.sh
, в функции database_ready
.
until database_ready DATABASE_URL; do
>&2 echo "Main DB is unavailable - sleeping"
sleep 1
done
Это будет только продолжаться, ЕСЛИ postgres запущен и работает. Как насчет оракула? То же самое, под кодом выше, мы добавляем:
until database_ready DATABASE_OTHER_URL; do
>&2 echo "Secondary DB is unavailable - sleeping"
sleep 1
done
Делая это таким образом, вы получите пару преимуществ:
вам не нужно беспокоиться о других зависимостях, таких как двоичные файлы и тому подобное.
Вы можете переключать базы данных и не беспокоиться об этом нарушении. (код не зависит от базы данных)
У меня был более сложный случай, когда я использую mongodb за модулем djongo и RDS mysql. Так что это не только несколько баз данных, но и djongo выдает ошибку SQLDecode. Я также должен был выполнить и получить, чтобы это работало:
from django.conf import settings
if settings.DEBUG:
# Quick database check here
from django.db import connections
from django.db.utils import OperationalError
dbs = settings.DATABASES.keys()
for db in dbs:
db_conn = connections[db] # i.e. default
try:
c = db_conn.cursor()
c.execute("""SELECT "non_existent_table"."id" FROM "non_existent_table" LIMIT 1""")
c.fetchone()
print("Database '{}' connection ok.".format(db)) # This case is for djongo decoding sql ok
except OperationalError as e:
if 'no such table' in str(e):
print("Database '{}' connection ok.".format(db)) # This is ok, db is present
else:
raise # Another type of op error
except Exception: # djongo sql decode error
print("ERROR: Database {} looks to be down.".format(db))
raise
Я загружаю это в свое приложение __init__.py
, так как хочу, чтобы оно запускалось при запуске только один раз и только если включена функция DEBUG. Надеюсь, поможет!
Кажется, ответ Хавьера больше не работает. Тот, который я собрал, чтобы выполнить задачу проверки доступности базы данных в точке входа Docker, предполагая, что у вас есть библиотека psycopg2
(например, вы запускаете приложение Django):
function database_ready() {
python << EOF
import psycopg2
try:
db = psycopg2.connect(host="$1", port="$2", dbname="$3", user="$4", password="$5")
except:
exit(1)
exit(0)
EOF
}
until database_ready $DATABASE_HOST $DATABASE_PORT $DATABASE_NAME $DATABASE_USER $DATABASE_PASSWORD; do
>&2 echo "Database is unavailable at $DATABASE_HOST:$DATABASE_PORT/$DATABASE_NAME - sleeping..."
sleep 1
done
echo "Database is ready - $DATABASE_HOST:$DATABASE_PORT/$DATABASE_NAME"'''