Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add single user server spawn delay and user-facing message #825

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
74 changes: 74 additions & 0 deletions kubespawner/spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import re
import string
import sys
import textwrap
import warnings
from functools import partial
from typing import Optional, Tuple, Type
Expand Down Expand Up @@ -1688,6 +1689,51 @@ def _validate_image_pull_secrets(self, proposal):
""",
)

server_spawn_launch_delay = Integer(
0,
config=True,
help="""
Time in seconds to delay a single-user server launch, which can be
useful for debugging. If set to zero, no delay will take place.
""",
)

server_spawn_launch_timer_enabled = Bool(
True,
config=True,
help="""
Enable the spawn progress counter message.
""",
)

server_spawn_launch_timer_threshold = Integer(
60,
config=True,
help="""
Time in seconds to wait before injecting a 'please be patient' message
to display to the user.
""",
)

server_spawn_launch_timer_frequency = Integer(
5,
config=True,
help="""
Sets a delay of N seconds between updates to the message buffer, so
that we don't spam the user with too many messages.
""",
)

server_spawn_launch_timer_message = Unicode(
"Server launch is taking longer than expected. Please be patient! Current time spent waiting: XXX seconds.",
config=True,
help="""
The injected timing message to display to the user. The string XXX
will be replaced by the number of seconds the spawn has taken in
self.progress().
""",
)

# deprecate redundant and inconsistent singleuser_ and user_ prefixes:
_deprecated_traits_09 = [
"singleuser_working_dir",
Expand Down Expand Up @@ -2306,6 +2352,9 @@ async def progress(self):
progress = 0
next_event = 0

# count in seconds to time single user server spawn duration
timer = 0

break_while_loop = False
while True:
# This logic avoids a race condition. self._start() will be invoked by
Expand All @@ -2322,6 +2371,23 @@ async def progress(self):
if start_future and start_future.done():
break_while_loop = True

# if the timer is greater than self.server_spawn_launch_timer_threshold
# display a message to the user with an incrementing count in seconds
if (
timer >= self.server_spawn_launch_timer_threshold
and self.server_spawn_launch_timer_enabled
):
# don't spam the user, so only update the timer message every few seconds
if timer % self.server_spawn_launch_timer_frequency == 0:
patience_message = textwrap.dedent(
self.server_spawn_launch_timer_message
)
patience_message.replace('XXX', str(timer))

yield {
'message': patience_message,
}

events = self.events
len_events = len(events)
if next_event < len_events:
Expand All @@ -2348,6 +2414,7 @@ async def progress(self):

if break_while_loop:
break
timer += 1
await asyncio.sleep(1)

async def _start_reflector(
Expand Down Expand Up @@ -2663,6 +2730,13 @@ async def _make_create_resource_request(self, kind, manifest):

async def _start(self):
"""Start the user's pod"""
# delay single user server spawn if testing
if self.server_spawn_launch_delay:
self.log.info(
"Delaying spawn launch for %s seconds.",
str(self.server_spawn_launch_delay),
)
await asyncio.sleep(self.server_spawn_launch_delay)

# load user options (including profile)
await self.load_user_options()
Expand Down