19👍
You are on the right track with using a router. I’m assuming the fact that your two db definitions are identical is just a typo.
(FYI, I’m going to refer to the database hierarchy using the more sensitive master->follower)
In your db_for_read() functions, you can check for connectivity to your follower. This might incur a bit more overhead, but that’s the cost of having auto-failover for a database. An example database definition would be:
DATABASES = {
'follower': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'follower',
'USER': 'root',
'HOST': '54.34.65.24',
'PORT': '3306',
},
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'application',
'USER': 'root',
'HOST': '54.34.65.23',
'PORT': '3306',
},
}
You can test the connection with a quick try/except like this example. A router using this that does what you need would look like:
from django.conf import settings
import socket
def test_connection_to_db(database_name):
try:
db_definition = getattr(settings, 'DATABASES')[database_name]
s = socket.create_connection((db_definition['HOST'], db_definition['PORT']), 5)
s.close()
return True
except (AttributeError, socket.timeout) as e:
return False
class FailoverRouter(object):
"""A router that defaults reads to the follower but provides a failover back to the default"""
def db_for_read(self, model, **hints):
if test_connection_to_db('follower'):
return 'follower'
return 'default'
def db_for_write(self, model, **hints):
"Point all writes to the default db"
return 'default'
def allow_syncdb(self, db, model):
"Make sure only the default db allows syncdb"
return db == 'default'
This will still syncdb in master like you want. Also, you could make the logic for both db_for_read()
and db_for_write()
more complicated (like pick the follower db only for certain models that are queried for your reports.
I don’t know what overhead this test_connection()
will cause for every read, since that will depend on the MySQL server and the timeout. Perhaps a better architecture is to cache these reports using memcached, or just work out the issues with the slave ever going down and update your database definitions in settings first.