docs: def _handle_tag_master_disconnected_failback(self, tag, data):
          '''
          Handle a master_disconnected_failback event
          '''
          # if the master disconnect event is for a different master, raise an exception
          if tag.startswith(master_event(type='disconnected')) and data['master'] != self.opts['master']:
              # not mine master, ignore
              return
          if tag.startswith(master_event(type='failback')):
              # if the master failback event is not for the top master, raise an exception
              if data['master'] != self.opts['master_list'][0]:
                  raise SaltException('Bad master \'{0}\' when mine failback is \'{1}\''.format(
                      data['master'], self.opts['master']))
              # if the master failback event is for the current master, raise an exception
              elif data['master'] == self.opts['master'][0]:
                  raise SaltException('Already connected to \'{0}\''.format(data['master']))
  
          if self.connected:
              # we are not connected anymore
              self.connected = False
              log.info('Connection to master %s lost', self.opts['master'])
  
              # we can't use the config default here because the default '0' value is overloaded
              # to mean 'if 0 disable the job', but when salt detects a timeout it also sets up
              # these jobs
              master_alive_interval = self.opts['master_alive_interval'] or 60
  
              if self.opts['master_type'] != 'failover':
                  # modify the scheduled job to fire on reconnect
                  if self.opts['transport'] != 'tcp':
                      schedule = {
                         'function': 'status.master',
                         'seconds': master_alive_interval,
                         'jid_include': True,
                         'maxrunning': 1,
                         'return_job': False,
                         'kwargs': {'master': self.opts['master'],
                                     'connected': False}
                      }
                      self.schedule.modify_job(name=master_event(type='alive', master=self.opts['master']),
                                               schedule=schedule)
              else:
                  # delete the scheduled job to don't interfere with the failover process
                  if self.opts['transport'] != 'tcp':
                      self.schedule.delete_job(name=master_event(type='alive', master=self.opts['master']),
                                               persist=True)
  
                  log.info('Trying to tune in to next master from master-list')
  
                  if hasattr(self, 'pub_channel'):
                      self.pub_channel.on_recv(None)
                      if hasattr(self.pub_channel, 'auth'):
                          self.pub_channel.auth.invalidate()
                      if hasattr(self.pub_channel, 'close'):
                          self.pub_channel.close()
                      del self.pub_channel
  
                  # if eval_master finds a new master for us, self.connected
                  # will be True again on successful master authentication
                  try:
                      master, self.pub_channel = yield self.eval_master(
                                                          opts=self.opts,
                                                          failed=True,
                                                          failback=tag.startswith(master_event(type='failback')))
                  except SaltClientError:
                      pass
  
                  if self.connected:
                      self.opts['master'] = master
  
                      # re-init the subsystems to work with the new master
                      log.info(
                          'Re-initialising subsystems for new master %s',
                          self.opts['master']
                      )
                      # put the current schedule into the new loaders
                      self.opts['schedule'] = self.schedule.option('schedule')
                      self.functions, self.returners, self.function_errors, self.executors = self._load_modules()
                      # make the schedule to use the new 'functions' loader
                      self.schedule.functions = self.functions
                      self.pub_channel.on_recv(self._handle_payload)
                      self._fire_master_minion_start()
                      log.info('Minion is ready to receive requests!')
  
                      # update scheduled job to run with the new master addr
                      if self.opts['transport'] != 'tcp':
                          schedule = {
                             'function': 'status.master',
                             'seconds': master_alive_interval,
                             'jid_include': True,
                             'maxrunning': 1,
                             'return_job': False,
                             'kwargs': {'master': self.opts['master'],
                                         'connected': True}
                          }
                          self.schedule.modify_job(name=master_event(type='alive', master=self.opts['master']),
                                                   schedule=schedule)
  
                          if self.opts['master_failback'] and 'master_list' in self.opts:
                              if self.opts['master'] != self.opts['master_list'][0]:
                                  schedule = {
                                     'function': 'status.ping_master',
                                     'seconds': self.opts['master_failback_interval'],
                                     'jid_include': True,
                                     'maxrunning': 1,
                                     'return_job': False,
                                     'kwargs': {'master': self.opts['master_list'][0]}
                                  }
                                  self.schedule.modify_job(name=master_event(type='failback'),
                                                           schedule=schedule)
                              else:
                                  self.schedule.delete_job(name=master_event(type='failback'), persist=True)
                  else:
                      self.restart = True
                      self.io_loop.stop()