Skip to content

Commit 05fc602

Browse files
committed
Initial commit
1 parent b0dd84d commit 05fc602

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aiohttp
2+
aiometer

simulate.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import argparse
2+
import asyncio
3+
from functools import partial
4+
import aiometer
5+
from datetime import datetime
6+
from typing import List, override
7+
import aiohttp
8+
import os
9+
import json
10+
from yarl import URL
11+
from dataclasses import dataclass
12+
13+
14+
@dataclass
15+
class ServerStartResult:
16+
servername: str
17+
username: str
18+
start_time: datetime
19+
completion_time: datetime
20+
started_successfully: bool
21+
events: List[dict]
22+
23+
@property
24+
def startup_duration(self):
25+
return self.completion_time - self.start_time
26+
27+
@override
28+
def __str__(self) -> str:
29+
return f"user:{self.username} server:{self.servername} started:{self.started_successfully} startup_duration:{self.startup_duration}"
30+
31+
async def start_named_server(session: aiohttp.ClientSession, hub_url: URL, username: str, server_name: str) -> ServerStartResult:
32+
"""
33+
Try to start a named server as defined
34+
35+
"""
36+
server_api_url = hub_url / "hub/api/users" / username / "servers" / server_name
37+
events = []
38+
async with session.post(server_api_url) as resp:
39+
start_time = datetime.now()
40+
if resp.status == 202:
41+
# we are awaiting start, let's look for events
42+
print(f"server {server_name} waiting to start")
43+
async with session.get(server_api_url / "progress") as progress_resp:
44+
async for line in progress_resp.content:
45+
if line.decode().strip() == '':
46+
# Empty line, just continue
47+
continue
48+
progress_event = json.loads(line.decode().strip()[len("data: "):])
49+
events.append(progress_event)
50+
if progress_event.get("ready") == True:
51+
return ServerStartResult(
52+
username=username,
53+
servername=server_name,
54+
start_time=start_time,
55+
completion_time=datetime.now(),
56+
started_successfully=True,
57+
events=events
58+
)
59+
elif resp.status == 201:
60+
# Means the server is immediately ready, and i don't want to deal with that yet
61+
raise NotImplementedError()
62+
63+
64+
async def main():
65+
argparser = argparse.ArgumentParser()
66+
argparser.add_argument("hub_url", help="Full URL to the JupyterHub to test against")
67+
argparser.add_argument("username", help="Name of the user")
68+
argparser.add_argument("servers_count", type=int, help="Number of servers to start")
69+
argparser.add_argument("--max-concurrency", type=int, default=30, help="Max Numbers of Servers to start at the same time")
70+
71+
args = argparser.parse_args()
72+
73+
token = os.environ["JUPYTERHUB_TOKEN"]
74+
75+
hub_url = URL(args.hub_url)
76+
async with aiohttp.ClientSession(headers={
77+
"Authorization": f"token {token}"
78+
}) as session:
79+
servernames = [f"perf-test-{i}" for i in range (args.servers_count)]
80+
async with aiometer.amap(partial(start_named_server, session, hub_url, args.username), servernames, max_at_once=args.max_concurrency) as servers:
81+
async for server in servers:
82+
print(server)
83+
84+
if __name__ == "__main__":
85+
asyncio.run(main())

0 commit comments

Comments
 (0)