Skip to content

Commit 7e3f2ef

Browse files
committed
updated to use fastuser and token caching, refreshing and sharing
1 parent f81aa17 commit 7e3f2ef

3 files changed

Lines changed: 40 additions & 10 deletions

File tree

tests/perf_tests/Makefile

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
1+
USERS ?= 250
2+
SPAWN_RATE ?= 50
3+
RUN_TIME ?= 5m
4+
5+
# Interactive UI — single process, useful for smoke tests
16
test:
27
poetry run locust -f src/locustfile.py
38

9+
# Interactive UI — search only
410
test-read-only:
511
poetry run locust -f src/locustfile.py SearchUser
612

7-
.PHONY: test test-read-only
13+
# Headless distributed — master + N workers, runs for 5 minutes then exits
14+
test-headless:
15+
poetry run locust -f src/locustfile.py \
16+
--headless \
17+
--users $(USERS) \
18+
--spawn-rate $(SPAWN_RATE) \
19+
--run-time $(RUN_TIME)
20+
21+
# Search-only headless distributed
22+
test-read-only-headless:
23+
poetry run locust -f src/locustfile.py SearchUser \
24+
--headless \
25+
--users $(USERS) \
26+
--spawn-rate $(SPAWN_RATE) \
27+
--run-time $(RUN_TIME)
28+
29+
.PHONY: test test-read-only test-headless test-read-only-headless

tests/perf_tests/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ This project contains Locust performance tests for the Immunisation FHIR API.
55
To run them, ensure you have the
66
`APIGEE_ENVIRONMENT` : Currently, only the ref environment is supported.
77
`PERF_CREATE_RPS_PER_USER` : numeric
8+
`PERF_SEARCH_RPS_PER_USER` : numeric
89

9-
env vars set, and call `make test`.
10+
env vars set, and call `PERF_SEARCH_RPS_PER_USER=1 make test-read-only-headless`.

tests/perf_tests/src/locustfile.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import gevent.lock
1212
import pandas as pd
1313
from botocore.config import Config
14-
from locust import HttpUser, constant_throughput, events, task
14+
from locust import constant_throughput, events, task
15+
from locust.contrib.fasthttp import FastHttpUser
16+
from locust.runners import WorkerRunner
1517

1618
from common.api_clients.authentication import AppRestrictedAuth
1719

@@ -29,7 +31,7 @@
2931

3032
_BOTO_CONFIG = Config(
3133
max_pool_connections=50, # default is 10; needs to exceed max concurrent Locust users
32-
retries={"mode": "standard", "max_attempts": 3},
34+
retries={"mode": "standard", "max_attempts": 1},
3335
)
3436
_secrets_client = boto3.client(
3537
"secretsmanager",
@@ -38,6 +40,7 @@
3840
)
3941

4042
PERF_CREATE_TASK_RPS_PER_USER = float(os.getenv("PERF_CREATE_RPS_PER_USER", "1"))
43+
PERF_SEARCH_RPS_PER_USER = float(os.getenv("PERF_SEARCH_RPS_PER_USER", "1"))
4144

4245
IMMUNIZATION_TARGETS = [
4346
"3IN1",
@@ -112,7 +115,13 @@ def get_access_token(self) -> str:
112115

113116
@events.init.add_listener
114117
def _pre_warm_auth(environment, **kwargs):
115-
"""Fetch token once before users spawn so all users start with a cached token."""
118+
"""Fetch token once before users spawn so all users start with a cached token.
119+
Only runs on master/standalone — workers fetch lazily on first request,
120+
staggered by the on_start jitter, avoiding simultaneous Secrets Manager calls.
121+
"""
122+
if isinstance(environment.runner, WorkerRunner):
123+
return
124+
116125
try:
117126
token = _shared_token_manager.get_access_token()
118127
print(f"[perf] Auth pre-warm complete. Token length: {len(token)}")
@@ -126,16 +135,14 @@ def _pre_warm_auth(environment, **kwargs):
126135
"\n[perf] FATAL: AWS credentials expired or inaccessible.\n"
127136
f" Error: {exc}\n\n"
128137
" Fix: run one of the following, then retry 'make test':\n"
129-
" aws sso login --sso-session akshay-sso\n"
130138
" aws sso login --profile <your-profile-name>\n",
131139
file=sys.stderr,
132140
)
133141
sys.exit(1)
134-
# Non-credential error — re-raise so it's not silently swallowed
135142
raise
136143

137144

138-
class BaseImmunizationUser(HttpUser):
145+
class BaseImmunizationUser(FastHttpUser):
139146
abstract = True
140147

141148
# token_manager = LocustTokenManager(
@@ -164,7 +171,7 @@ def on_start(self):
164171

165172
def _build_create_payload(self):
166173
immunization_target = random.choice(IMMUNIZATION_TARGETS)
167-
patient = load_patient_by_id(random.choice(VALID_PATIENT_IDS))
174+
patient = load_patient_by_id("Valid_NHS")
168175
immunization = create_immunization_object(patient, immunization_target)
169176
return json.loads(immunization.json(exclude_none=True))
170177

@@ -183,7 +190,7 @@ def _delete_created_immunization(self, immunization_id: str):
183190

184191

185192
class SearchUser(BaseImmunizationUser):
186-
wait_time = constant_throughput(1)
193+
wait_time = constant_throughput(PERF_SEARCH_RPS_PER_USER)
187194

188195
@task
189196
def search_single_vacc_type(self):

0 commit comments

Comments
 (0)