Cleanly disconnects and then reconnects.

async def _reconnect(self, last_error):
        """
        Cleanly disconnects and then reconnects.
        """
        self._log.debug('Closing current connection...')
        await self._connection.disconnect()

        await helpers._cancel(
            self._log,
            send_loop_handle=self._send_loop_handle,
            recv_loop_handle=self._recv_loop_handle
        )

        # TODO See comment in `_start_reconnect`
        # Perhaps this should be the last thing to do?
        # But _connect() creates tasks which may run and,
        # if they see that reconnecting is True, they will end.
        # Perhaps that task creation should not belong in connect?
        self._reconnecting = False

        # Start with a clean state (and thus session ID) to avoid old msgs
        self._state.reset()

        retries = self._retries if self._auto_reconnect else 0
        for attempt in retry_range(retries):
            try:
                await self._connect()
            except (IOError, asyncio.TimeoutError) as e:
                last_error = e
                self._log.info('Failed reconnection attempt %d with %s',
                               attempt, e.__class__.__name__)

                await asyncio.sleep(self._delay)
            except Exception as e:
                last_error = e
                self._log.exception('Unexpected exception reconnecting on '
                                    'attempt %d', attempt)

                await asyncio.sleep(self._delay)
            else:
                self._send_queue.extend(self._pending_state.values())
                self._pending_state.clear()

                if self._auto_reconnect_callback:
                    self._loop.create_task(self._auto_reconnect_callback())

                break
        else:
            self._log.error('Automatic reconnection failed {} time(s)'
                            .format(attempt))
            await self._disconnect(error=last_error.with_traceback(None))