Skip to content

Commit c03b399

Browse files
michael.yakmichaelyaakoby
authored andcommitted
First registration shouldn't block the application using SBA
When pyctuator is starting up, it starts sending periodic registration requests to SBA. Currently, the first registration is done on the "main thread" while subsequent registrations are done asynchronously (using a "daemonic" `threading.Timer()`. If the registration's HTTP request is stuck until timing out, this blocks the application until the this timeout. Instead, all registration attempts, including the first one, should be done asynchronously. See #51
1 parent a1e8ade commit c03b399

File tree

9 files changed

+25
-17
lines changed

9 files changed

+25
-17
lines changed

examples/Advanced/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ python = "^3.7"
1111
psutil = { version = "^5.6" }
1212
fastapi = { version = "^0.41.0" }
1313
uvicorn = { version = "^0.9.0" }
14-
pyctuator = { version = "^0.13.4" }
14+
pyctuator = { version = "^0.13.5" }
1515
sqlalchemy = { version = "^1.3" }
1616
PyMySQL = { version = "^0.9.3" }
1717
cryptography = { version = "^2.8" }

examples/FastAPI/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ python = "^3.7"
1111
psutil = { version = "^5.6" }
1212
fastapi = { version = "^0.41.0" }
1313
uvicorn = { version = "^0.9.0" }
14-
pyctuator = { version = "^0.13.4" }
14+
pyctuator = { version = "^0.13.5" }
1515

1616
[build-system]
1717
requires = ["poetry>=0.12"]

examples/Flask/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors = [
1010
python = "^3.7"
1111
psutil = { version = "^5.6" }
1212
flask = { version = "^1.1" }
13-
pyctuator = { version = "^0.13.4" }
13+
pyctuator = { version = "^0.13.5" }
1414

1515
[build-system]
1616
requires = ["poetry>=0.12"]

examples/aiohttp/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors = [
1010
python = "^3.7"
1111
psutil = { version = "^5.6" }
1212
aiohttp = { version = "^3.5.4" }
13-
pyctuator = { version = "^0.13.4" }
13+
pyctuator = { version = "^0.13.5" }
1414

1515
[build-system]
1616
requires = ["poetry>=0.12"]

examples/tornado/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors = [
1010
python = "^3.7"
1111
psutil = { version = "^5.6" }
1212
tornado = { version = "^6.0.4" }
13-
pyctuator = { version = "^0.13.4" }
13+
pyctuator = { version = "^0.13.5" }
1414

1515
[build-system]
1616
requires = ["poetry>=0.12"]

pyctuator/impl/spring_boot_admin_registration.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def __init__(
2424
pyctuator_base_url: str,
2525
start_time: datetime,
2626
service_url: str,
27-
registration_interval_sec: int,
27+
registration_interval_sec: float,
2828
application_metadata: Optional[dict] = None
2929
) -> None:
3030
self.registration_url = registration_url
@@ -41,7 +41,7 @@ def __init__(
4141
self.disable_certificate_validation_for_https_registration: bool = \
4242
os.getenv("PYCTUATOR_REGISTRATION_NO_CERT") is not None
4343

44-
def _schedule_next_registration(self, registration_interval_sec: int) -> None:
44+
def _schedule_next_registration(self, registration_interval_sec: float) -> None:
4545
timer = threading.Timer(
4646
registration_interval_sec,
4747
self._register_with_admin_server,
@@ -66,8 +66,7 @@ def _register_with_admin_server(self) -> None:
6666
}
6767
}
6868

69-
logging.debug("Trying to post registration data to %s: %s",
70-
self.registration_url, registration_data)
69+
logging.debug("Trying to post registration data to %s: %s", self.registration_url, registration_data)
7170

7271
conn: Optional[HTTPConnection] = None
7372
try:
@@ -123,11 +122,11 @@ def authenticate(self, headers: Dict) -> None:
123122
encoded_authorization: str = b64encode(bytes(authorization_string, "utf-8")).decode("ascii")
124123
headers["Authorization"] = f"Basic {encoded_authorization}"
125124

126-
def start(self) -> None:
125+
def start(self, initial_delay_sec: float = None) -> None:
127126
logging.info("Starting recurring registration of %s with %s",
128127
self.pyctuator_base_url, self.registration_url)
129128
self.should_continue_registration_schedule = True
130-
self._register_with_admin_server()
129+
self._schedule_next_registration(initial_delay_sec or self.registration_interval_sec)
131130

132131
def stop(self) -> None:
133132
logging.info("Stopping recurring registration")

pyctuator/pyctuator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(
3333
registration_url: Optional[str],
3434
registration_auth: Optional[Auth] = None,
3535
app_description: Optional[str] = None,
36-
registration_interval_sec: int = 10,
36+
registration_interval_sec: float = 10,
3737
free_disk_space_down_threshold_bytes: int = 1024 * 1024 * 100,
3838
logfile_max_size: int = 10000,
3939
logfile_formatter: str = default_logfile_format,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pyctuator"
3-
version = "0.13.4"
3+
version = "0.13.5"
44
description = "A Python implementation of the Spring Actuator API for popular web frameworks"
55
authors = [
66
"Michael Yakobi <[email protected]>",

tests/test_spring_boot_admin_registration.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import time
12
from datetime import datetime
23
from typing import Optional, Any
34

@@ -13,7 +14,7 @@ def test_registration_no_auth(registration_tracker: RegistrationTrackerFixture)
1314
registration_handler = get_registration_handler("http://localhost:8001/register", None)
1415

1516
try:
16-
registration_handler.start()
17+
_start_registration(registration_handler)
1718
assert registration_tracker.count == 1
1819

1920
finally:
@@ -25,7 +26,7 @@ def test_registration_basic_auth_no_creds(registration_tracker: RegistrationTrac
2526
registration_handler = get_registration_handler("http://localhost:8001/register-with-basic-auth", None)
2627

2728
try:
28-
registration_handler.start()
29+
_start_registration(registration_handler)
2930
assert registration_tracker.count == 0
3031

3132
error_message = "Failed registering with boot-admin, got %s - %s"
@@ -46,7 +47,7 @@ def test_registration_basic_auth_bad_creds(registration_tracker: RegistrationTra
4647
)
4748

4849
try:
49-
registration_handler.start()
50+
_start_registration(registration_handler)
5051
assert registration_tracker.count == 0
5152

5253
error_message = "Failed registering with boot-admin, got %s - %s"
@@ -67,7 +68,7 @@ def test_registration_basic_auth(registration_tracker: RegistrationTrackerFixtur
6768
)
6869

6970
try:
70-
registration_handler.start()
71+
_start_registration(registration_handler)
7172
assert registration_tracker.count == 1
7273

7374
finally:
@@ -84,3 +85,11 @@ def get_registration_handler(registration_url: str, registration_auth: Optional[
8485
service_url="http://whatever/service",
8586
registration_interval_sec=100
8687
)
88+
89+
90+
def _start_registration(registration_handler: BootAdminRegistrationHandler) -> None:
91+
# Registration is done asynchronously, for the test, ask to register shortly after start is called
92+
registration_handler.start(0.01)
93+
94+
# Wait enough after starting the registration allowing the async registration to happen.
95+
time.sleep(0.1)

0 commit comments

Comments
 (0)