    async def init_spawners(self):
        self.log.debug("Initializing spawners")
        db = self.db

        def _user_summary(user):
            """user is an orm.User, not a full user"""
            parts = [f'{user.name: >8}']
            if user.admin:
                parts.append('admin')
            for name, spawner in sorted(user.orm_spawners.items(), key=itemgetter(0)):
                if spawner.server:
                    parts.append(f'{user.name}:{name} running at {spawner.server}')
            return ' '.join(parts)

        async def user_stopped(user, server_name):
            spawner = user.spawners[server_name]
            status = await spawner.poll()
            self.log.warning(
                "User %s server stopped with exit code: %s", user.name, status
            )
            await self.proxy.delete_user(user, server_name)
            await user.stop(server_name)

        async def check_spawner(user, name, spawner):
            status = 0
            if spawner.server:
                if user.name in self.authenticator.blocked_users:
                    self.log.warning(
                        f"Stopping spawner for blocked user: {spawner._log_name}"
                    )
                    try:
                        await user.stop(name)
                    except Exception:
                        self.log.exception(
                            f"Failed to stop {spawner._log_name}",
                            exc_info=True,
                        )
                    return
                try:
                    status = await spawner.poll()
                except Exception:
                    self.log.exception(
                        "Failed to poll spawner for %s, assuming the spawner is not running.",
                        spawner._log_name,
                    )
                    status = -1

            if status is None:
                # poll claims it's running.
                # Check if it's really there
                url_in_db = spawner.server.url
                url = await spawner.get_url()
                if url != url_in_db:
                    self.log.warning(
                        "%s had invalid url %s. Updating to %s",
                        spawner._log_name,
                        url_in_db,
                        url,
                    )
                    urlinfo = urlparse(url)
                    spawner.server.protocol = urlinfo.scheme
                    spawner.server.ip = urlinfo.hostname
                    if urlinfo.port:
                        spawner.server.port = urlinfo.port
                    elif urlinfo.scheme == 'http':
                        spawner.server.port = 80
                    elif urlinfo.scheme == 'https':
                        spawner.server.port = 443
                    self.db.commit()

                self.log.debug(
                    "Verifying that %s is running at %s", spawner._log_name, url
                )
                try:
                    await user._wait_up(spawner)
                except AnyTimeoutError:
                    self.log.error(
                        "%s does not appear to be running at %s, shutting it down.",
                        spawner._log_name,
                        url,
                    )
                    status = -1

            if status is None:
                self.log.info("%s still running", user.name)
                spawner.add_poll_callback(user_stopped, user, name)
                spawner.start_polling()
            else:
                # user not running. This is expected if server is None,
                # but indicates the user's server died while the Hub wasn't running
                # if spawner.server is defined.
                if spawner.server:
                    self.log.warning(
                        "%s appears to have stopped while the Hub was down",
                        spawner._log_name,
                    )
                    try:
                        await user.stop(name)
                    except Exception:
                        self.log.exception(
                            f"Failed to cleanup {spawner._log_name} which appeared to stop while the Hub was down.",
                            exc_info=True,
                        )
                else:
                    self.log.debug("%s not running", spawner._log_name)

            spawner._check_pending = False

        # parallelize checks for running Spawners
        # run query on extant Server objects
        # so this is O(running servers) not O(total users)
        # Server objects can be associated with either a Spawner or a Service,
        # we are only interested in the ones associated with a Spawner
        check_futures = []

        for orm_user, orm_spawner in (
            self.db.query(orm.User, orm.Spawner)
            # join filters out any Users with no Spawners
            .join(orm.Spawner, orm.User._orm_spawners)
            # this gets Users with *any* active server
            .filter(orm.Spawner.server != None)
            # pre-load relationships to avoid O(N active servers) queries
            .options(
                joinedload(orm.User._orm_spawners),
                joinedload(orm.Spawner.server),
            )
        ):
            # instantiate Spawner wrapper and check if it's still alive
            # spawner should be running
            user = self.users[orm_user]
            spawner = user.spawners[orm_spawner.name]
            self.log.debug("Loading state for %s from db", spawner._log_name)
            # signal that check is pending to avoid race conditions
            spawner._check_pending = True
            f = asyncio.ensure_future(check_spawner(user, spawner.name, spawner))
            check_futures.append(f)

        # it's important that we get here before the first await
        # so that we know all spawners are instantiated and in the check-pending state

        # await checks after submitting them all
        if check_futures:
            self.log.debug(
                "Awaiting checks for %i possibly-running spawners", len(check_futures)
            )
            await asyncio.gather(*check_futures)
        db.commit()

        # only perform this query if we are going to log it
        if self.log_level <= logging.DEBUG:
            user_summaries = map(_user_summary, self.users.values())
            self.log.debug("Loaded users:\n%s", '\n'.join(user_summaries))

        active_counts = self.users.count_active_users()
        RUNNING_SERVERS.set(active_counts['active'])
        return len(check_futures)
user is an orm.User, not a full user
jupyterhub/app.py