如何优雅地处理OperationalError 2003并使用.using()更改数据库

时间:2017-05-09 23:09:09

标签: python mysql django python-3.x

假设您在网站the-app上有一个Django 1.11应用the-site

the-site/settings.py中,您有以下数据库:

DATABASES = {                                                                   
 'default': {                                                                
     'ENGINE': 'django.db.backends.mysql',                                   
     'NAME': 'the-site_webapp',                                                   
     'USER': 'tester',                                                       
     'PASSWORD': '',                                                         
     'HOST': 'localhost',                                                    
     'PORT': '3306',                                                                                                
 },                                                                          
 'remote-db1': {                                                                
     'ENGINE': 'django.db.backends.mysql',                                   
     'NAME': 'remote-db1',                                                      
     'USER': 'tester',                                                       
     'PASSWORD': '',                                                
     'HOST': '<ip1>',    
     'PORT': '3306',                                      
 },
 'remote-db2': {                                                                
     'ENGINE': 'django.db.backends.mysql',                                   
     'NAME': 'remote-db2',                                                      
     'USER': 'tester',                                                       
     'PASSWORD': '',                                                
     'HOST': '<ip2>',    
     'PORT': '3306',                                      
 },
}

其中remote-db2包含remote-db1的受限子集,因此可以替代它。

还有以下路由器信息:

DATABASE_ROUTERS = [ 'the-app.routers.DefaultRouter', 'the-app.routers.the-appRouter',]

指向the-app/routers.py

class MasterRouter(object):                                                                                            
 '''                                                                         
 https://stackoverflow.com/questions/13988432/how-to-use-db-router-in-django-1-4
 '''                                                                         
 def __init__(self, app_label, db_name):                                     
     super(MasterRouter, self).__init__()                                    
     self.app_label = app_label                                              
     self.db_name = db_name                                                  


 def db_for_read(self, model, **hints):                                      
     if model._meta.app_label == self.app_label:                             
         return self.db_name                                                 
         #return self.app_label                                              
     return None                                                             

 def db_for_write(self, model, **hints):                                     
     if model._meta.app_label == self.app_label:                             
         return self.db_name                                                 

     return None                                                             

 def allow_relation(self, obj1, obj2, **hints):                              
     if obj1._meta.app_label == self.app_label or obj2._meta.app_label == self.app_label:
         return True                                                         
     return None                                                             

 def allow_syncdb(self, db, model):                                          
     if db == 'default':                                                     
         return model._meta.app_label == self.app_label                      
     elif model._meta.app_label == self.app_label:                           
         return False                                                        
     return None                                                             

 def allow_migrate(self, db, *args, **kwargs):                               
     if db in ['remote-db1']:                                            
         return False     


class DefaultRouter(MasterRouter):                                              
 def __init__(self):                                                         
     super(DefaultRouter, self).__init__('default', 'default')               

class the-appRouter(MasterRouter):                                                  
 def __init__(self):                                                                                       
     super(the-appRouter, self).__init__('the-app', 'remote-db1')                       

the-app/views.py中,您有:

def foo (request):
    try:              
     curfile = ModelName.objects.get(**arg_dict)                            
     return _fetch_info(request, curfile)                                    
    except (KeyError, ModelName.DoesNotExist) as e:       
         messages.add_message(request, messages.ERROR, 'Couldn\'t find sample in remote-db1; attempting to connect to remote-db2')
         try:                                                                    
             curfile = ModelName.objects.using('remote-db2').get(**arg_dict)       
             return _fetch_info(request, curfile)                                
         except (KeyError, ModelName.DoesNotExist) as e:                        
             messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
             return render(request, 'foo.html')                            
         except (OperationalError,) as e:                                        
             messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db2.')
             traceback.print_exc() # debugging                                   
             return render(request, 'invalid.html')                              
     except (OperationalError) as e:                                             
          messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db1. Trying remote-db2.')
          traceback.print_exc() # debugging                                       
          try:                                                                    
             curfile = ModelName.objects.using('remote-db2').get(**arg_dict)       
             return _fetch_info(request, curfile)                                
          except (KeyError, SampleFile.DoesNotExist) as e:                          
              messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
              return render(request, 'view_info.html')                            
          except (OperationalError,) as e:                                        
              messages.add_message(request, messages.ERROR, 'Couldn\'t connect to either remote-db1 nor to remote-db2.')
              traceback.print_exc() # debugging                                   
              return render(request, 'invalid.html')

查看traceback日志,似乎发生的事情是,尽管我告诉Django .using('remote-db2')连接到remote-db2,但它会再次尝试连接remote-db1

在我的某个地方是否可以处理此OperationalError(代码2003)?它looks like(第205行)这可能是不可能的(ever),但必须有某种方式来优雅地处理这个,除了呈现错误页面说&#34;稍后再试#34;!

非常感谢你的阅读时间和任何帮助,你可以给我:)。

编辑:我不管理遗留数据库和新数据库,因此我无法在数据库端轻松实现任何类型的负载平衡或故障转移策略。我被引导到django-failover:github.com/brianjaystanley/django-failover(抱歉,由于n00b状态,在帖子中不能超过2个链接),但是我使用的是python 3.5并且必须更新包,如果它仍然适用于Django 1.11!此外,两个远程数据库的模式略有不同,尽管它们包含有关相同对象的信息,因此django-failover不适用。

相关帖子:

  1. stackoverflow.com/questions/18174910/django-database-routers-failover-scenario
  2. stackoverflow.com/questions/28554740/in-django-1-6-handle-mysql-failover-while-using-database-routers
  3. (我在发布此帖之前读过其他人,但问题与Django pointing to MySQL db at localhost的错误配置有关)

0 个答案:

没有答案