|
1 | 1 | from __future__ import annotations |
| 2 | +import random |
2 | 3 | import argparse |
3 | 4 | import asyncio |
4 | 5 | from enum import Enum |
|
9 | 10 | from datetime import datetime |
10 | 11 | from functools import partial |
11 | 12 | import time |
12 | | -from typing import List |
| 13 | +from typing import Any, Coroutine, List |
13 | 14 |
|
14 | 15 | import aiohttp |
15 | 16 | import aiometer |
@@ -160,6 +161,13 @@ async def start_named_server( |
160 | 161 | # Some kinda error |
161 | 162 | resp.raise_for_status() |
162 | 163 |
|
| 164 | +def poisson_distribution_wait_times(rate: float, count: int) -> list[float]: |
| 165 | + wait_times = [] |
| 166 | + t = 0 |
| 167 | + while(len(wait_times) < count): |
| 168 | + t += random.expovariate(rate) |
| 169 | + wait_times.append(t) |
| 170 | + return wait_times |
163 | 171 |
|
164 | 172 | async def payload( |
165 | 173 | session: aiohttp.ClientSession, |
@@ -193,13 +201,17 @@ async def payload( |
193 | 201 |
|
194 | 202 | print(f"{server.servername}: {timing_info}") |
195 | 203 |
|
| 204 | +async def delay(duration: float, callable: Coroutine) -> Any: |
| 205 | + await asyncio.sleep(duration) |
| 206 | + return await callable |
196 | 207 |
|
197 | 208 | async def main(): |
198 | 209 | argparser = argparse.ArgumentParser() |
199 | 210 | argparser.add_argument("hub_url", help="Full URL to the JupyterHub to test against") |
200 | 211 | argparser.add_argument("server_prefix", help="Prefix used for named servers started in this run") |
201 | 212 | argparser.add_argument("username", help="Name of the user") |
202 | 213 | argparser.add_argument("servers_count", type=int, help="Number of servers to start") |
| 214 | + argparser.add_argument("server_startup_rate", type=int, help="Number of servers to start per minute") |
203 | 215 | # FIXME: This shouldn't be here. |
204 | 216 | argparser.add_argument( |
205 | 217 | "--max-concurrency", |
@@ -233,10 +245,12 @@ async def main(): |
233 | 245 | Server(f"{args.server_prefix}-{i}", args.username, HubAccess(hub_url, token)) |
234 | 246 | for i in range(args.servers_count) |
235 | 247 | ] |
| 248 | + delays = poisson_distribution_wait_times(args.server_startup_rate / 60, args.servers_count) |
| 249 | + print(delays) |
236 | 250 | await aiometer.run_all( |
237 | 251 | [ |
238 | | - partial(payload, session, browser, token, nbgitpuller_url, profile_options, server) |
239 | | - for server in servers_to_start |
| 252 | + partial(delay, duration, payload(session, browser, token, nbgitpuller_url, profile_options, server)) |
| 253 | + for server, duration in zip(servers_to_start, delays) |
240 | 254 | ], |
241 | 255 | max_at_once=args.max_concurrency, |
242 | 256 | ) |
|
0 commit comments