    async def stop_single_user(self, user, server_name=''):
        if server_name not in user.spawners:
            raise KeyError("User %s has no such spawner %r", user.name, server_name)
        spawner = user.spawners[server_name]
        if spawner.pending:
            raise RuntimeError(f"{spawner._log_name} pending {spawner.pending}")
        # set user._stop_pending before doing anything async
        # to avoid races
        spawner._stop_pending = True

        async def stop():
            """Stop the server

            1. remove it from the proxy
            2. stop the server
            3. notice that it stopped
            """
            tic = time.perf_counter()
            try:
                await self.proxy.delete_user(user, server_name)
                PROXY_DELETE_DURATION_SECONDS.labels(
                    status=ProxyDeleteStatus.success
                ).observe(time.perf_counter() - tic)

                await user.stop(server_name)
                toc = time.perf_counter()
                self.log.info(
                    "User %s server took %.3f seconds to stop", user.name, toc - tic
                )
                self.statsd.timing('spawner.stop', (toc - tic) * 1000)
                SERVER_STOP_DURATION_SECONDS.labels(
                    status=ServerStopStatus.success
                ).observe(toc - tic)
                self.eventlog.emit(
                    schema_id='https://schema.jupyter.org/jupyterhub/events/server-action',
                    data={
                        'action': 'stop',
                        'username': user.name,
                        'servername': server_name,
                    },
                )
            except Exception:
                PROXY_DELETE_DURATION_SECONDS.labels(
                    status=ProxyDeleteStatus.failure
                ).observe(time.perf_counter() - tic)
                SERVER_STOP_DURATION_SECONDS.labels(
                    status=ServerStopStatus.failure
                ).observe(time.perf_counter() - tic)
            finally:
                spawner._stop_future = None
                spawner._stop_pending = False

        future = spawner._stop_future = asyncio.ensure_future(stop())

        try:
            await gen.with_timeout(timedelta(seconds=self.slow_stop_timeout), future)
        except AnyTimeoutError:
            # hit timeout, but stop is still pending
            self.log.warning(
                "User %s:%s server is slow to stop (timeout=%s)",
                user.name,
                server_name,
                self.slow_stop_timeout,
            )

        # return handle on the future for hooking up callbacks
        return future
Stop the server

1. remove it from the proxy
2. stop the server
3. notice that it stopped
jupyterhub/handlers/base.py