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()
Handle a master_disconnected_failback event