async def launch(self, provider):
        """Ask JupyterHub to launch the image."""
        quota_check = await self.check_quota(provider)

        if quota_check:
            if quota_check.matching >= 0.5 * quota_check.quota:
                log = app_log.warning
            else:
                log = app_log.info
            log(
                "Launching server for %s: %s other servers running this repo (%s total)",
                self.repo_url,
                quota_check.matching,
                quota_check.total,
            )

        await self.emit(
            {
                "phase": "launching",
                "message": "Launching server...\n",
            }
        )

        launcher = self.settings["launcher"]
        retry_delay = launcher.retry_delay
        for i in range(launcher.retries):
            launch_starttime = time.perf_counter()
            if self.settings["auth_enabled"]:
                # get logged in user's name
                user_model = self.hub_auth.get_user(self)
                username = user_model["name"]
                if launcher.allow_named_servers:
                    # user can launch multiple servers, so create a unique server name
                    server_name = launcher.unique_name_from_repo(self.repo_url)
                else:
                    server_name = ""
            else:
                # create a name for temporary user
                username = launcher.unique_name_from_repo(self.repo_url)
                server_name = ""
            try:

                async def handle_progress_event(event):
                    message = event["message"]
                    await self.emit(
                        {
                            "phase": "launching",
                            "message": message + "\n",
                        }
                    )

                extra_args = {
                    "binder_ref_url": self.ref_url,
                    "binder_launch_host": self.binder_launch_host,
                    "binder_request": self.binder_request,
                    "binder_persistent_request": self.binder_persistent_request,
                }
                server_info = await launcher.launch(
                    image=self.image_name,
                    username=username,
                    server_name=server_name,
                    repo_url=self.repo_url,
                    extra_args=extra_args,
                    event_callback=handle_progress_event,
                )
            except Exception as e:
                duration = time.perf_counter() - launch_starttime
                if i + 1 == launcher.retries:
                    status = "failure"
                else:
                    status = "retry"
                # don't count retries in failure/retry
                # retry count is only interesting in success
                LAUNCH_TIME.labels(
                    status=status,
                    retries=-1,
                ).observe(time.perf_counter() - launch_starttime)
                if status == "failure":
                    # don't count retries per repo
                    LAUNCH_COUNT.labels(
                        status=status,
                        **self.repo_metric_labels,
                    ).inc()

                if i + 1 == launcher.retries:
                    # last attempt failed, let it raise
                    raise

                # not the last attempt, try again
                app_log.error(
                    "Retrying launch of %s after error (duration=%.0fs, attempt=%s): %r",
                    self.repo_url,
                    duration,
                    i + 1,
                    e,
                )
                await self.emit(
                    {
                        "phase": "launching",
                        "message": f"Launch attempt {i + 1} failed, retrying...\n",
                    }
                )
                await gen.sleep(retry_delay)
                # exponential backoff for consecutive failures
                retry_delay *= 2
                continue
            else:
                # success
                duration = time.perf_counter() - launch_starttime
                LAUNCH_TIME.labels(status="success", retries=i).observe(duration)
                LAUNCH_COUNT.labels(
                    status="success",
                    **self.repo_metric_labels,
                ).inc()
                app_log.info("Launched %s in %.0fs", self.repo_url, duration)
                break
        event = {
            "phase": "ready",
            "message": f"server running at {server_info['url']}\n",
        }
        event.update(server_info)
        await self.emit(event)
Ask JupyterHub to launch the image.
binderhub/builder.py