Skip to content

Commit d5c82ca

Browse files
fix for update script, small refactor
1 parent a721a60 commit d5c82ca

3 files changed

Lines changed: 85 additions & 25 deletions

File tree

core/pioreactor/web/tasks.py

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -316,30 +316,11 @@ def _fanout_failure_from_response(
316316
)
317317

318318

319-
def _process_delayed_json_response(
319+
def _process_json_response(
320320
unit: str,
321321
response: Response,
322-
*,
323-
max_attempts: int = 300,
324-
retry_sleep_s: float = 0.1,
322+
data: dict[str, Any],
325323
) -> tuple[str, Any]:
326-
"""
327-
Handle delayed HTTP responses (202 with result_url_path) and immediate 2xx responses.
328-
Returns the unit and the appropriate JSON data or result value.
329-
"""
330-
data = response.json()
331-
if response.status_code == 202 and "result_url_path" in data:
332-
# Follow up shortly on async responses where the unit returns a result URL.
333-
if max_attempts <= 0:
334-
return unit, fanout_failure(
335-
unit,
336-
"task_timeout",
337-
"Timed out waiting for unit task result.",
338-
retryable=True,
339-
status_code=response.status_code,
340-
)
341-
sleep(retry_sleep_s)
342-
return _get_from_unit(unit, data["result_url_path"], max_attempts=max_attempts - 1)
343324
if 200 <= response.status_code < 300:
344325
if "task_id" in data:
345326
if data.get("status") == "succeeded":
@@ -371,6 +352,69 @@ def _process_delayed_json_response(
371352
)
372353

373354

355+
def _process_delayed_json_response(
356+
unit: str,
357+
address: str,
358+
response: Response,
359+
*,
360+
max_attempts: int,
361+
timeout: float,
362+
retry_sleep_s: float = 0.1,
363+
) -> tuple[str, Any]:
364+
"""
365+
Handle delayed HTTP responses (202 with result_url_path) and immediate 2xx responses.
366+
Returns the unit and the appropriate JSON data or result value.
367+
"""
368+
data = response.json()
369+
remaining_attempts = max_attempts
370+
371+
while response.status_code == 202 and "result_url_path" in data:
372+
if remaining_attempts <= 0:
373+
return unit, fanout_failure(
374+
unit,
375+
"task_timeout",
376+
"Timed out waiting for unit task result.",
377+
retryable=True,
378+
status_code=response.status_code,
379+
)
380+
381+
endpoint = data["result_url_path"]
382+
remaining_attempts -= 1
383+
sleep(retry_sleep_s)
384+
385+
delayed_response: Response | None = None
386+
try:
387+
delayed_response = get_from(address, endpoint, timeout=timeout)
388+
delayed_response.raise_for_status()
389+
response = delayed_response
390+
data = response.json()
391+
except (HTTPErrorStatus, HTTPException) as e:
392+
logger.debug(
393+
f"Could not get from {unit}'s {address=}, {endpoint=}, sent json=None and returned {e}."
394+
f"{_summarize_unit_api_error(delayed_response)}"
395+
)
396+
return unit, _fanout_failure_from_response(
397+
unit,
398+
delayed_response,
399+
fallback_kind="http_error" if delayed_response is not None else "connection_error",
400+
fallback_message=f"Could not GET from {unit}'s {endpoint}.",
401+
retryable=delayed_response is None or delayed_response.status_code >= 500,
402+
)
403+
except DecodeError:
404+
logger.debug(
405+
f"Could not decode response from {unit}'s {endpoint=}, sent json=None and returned {_response_body_for_logging(delayed_response)}."
406+
)
407+
return unit, fanout_failure(
408+
unit,
409+
"decode_error",
410+
f"Could not decode response from {unit}'s {endpoint}.",
411+
retryable=False,
412+
status_code=delayed_response.status_code if delayed_response is not None else None,
413+
)
414+
415+
return _process_json_response(unit, response, data)
416+
417+
374418
def _delayed_result_max_attempts(timeout: float, retry_sleep_s: float = 0.1) -> int:
375419
return max(1, math.ceil(timeout / retry_sleep_s))
376420

@@ -1559,7 +1603,13 @@ def post_into_unit(
15591603
return unit, fanout_success(unit, None)
15601604

15611605
# delayed or immediate JSON response
1562-
return _process_delayed_json_response(unit, r, max_attempts=_delayed_result_max_attempts(timeout))
1606+
return _process_delayed_json_response(
1607+
unit,
1608+
address,
1609+
r,
1610+
max_attempts=_delayed_result_max_attempts(timeout),
1611+
timeout=timeout,
1612+
)
15631613

15641614
except (HTTPErrorStatus, HTTPException) as e:
15651615
logger.debug(
@@ -1750,8 +1800,10 @@ def _get_from_unit(
17501800
# delayed or immediate JSON response
17511801
return _process_delayed_json_response(
17521802
unit,
1803+
address,
17531804
r,
17541805
max_attempts=max_attempts if max_attempts is not None else _delayed_result_max_attempts(timeout),
1806+
timeout=timeout,
17551807
)
17561808

17571809
except (HTTPErrorStatus, HTTPException) as e:
@@ -1874,7 +1926,13 @@ def patch_into_unit(
18741926
return unit, fanout_success(unit, None)
18751927

18761928
# delayed or immediate JSON response
1877-
return _process_delayed_json_response(unit, r, max_attempts=_delayed_result_max_attempts(timeout))
1929+
return _process_delayed_json_response(
1930+
unit,
1931+
address,
1932+
r,
1933+
max_attempts=_delayed_result_max_attempts(timeout),
1934+
timeout=timeout,
1935+
)
18781936

18791937
except (HTTPErrorStatus, HTTPException) as e:
18801938
logger.debug(

core/tests/web/test_app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ class DummyResponse:
3939
def json(self) -> dict[str, str]:
4040
return {"msg": "Calibration created successfully."}
4141

42-
assert mod._process_delayed_json_response("unit1", DummyResponse()) == (
42+
assert mod._process_delayed_json_response(
43+
"unit1", "http://unit.local", DummyResponse(), max_attempts=1, timeout=5.0
44+
) == (
4345
"unit1",
4446
{"ok": True, "unit": "unit1", "value": {"msg": "Calibration created successfully."}},
4547
)

core/update_scripts/upcoming/update.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ if [ "$HOSTNAME" != "$LEADER_HOSTNAME" ]; then
6868
fi
6969

7070

71-
sudo -u pioreactor pio log -m "Running some database optimizations during update process, this make take a few minutes, please be patient" -l notice
71+
sudo -u pioreactor -i pio log -m "Running some database optimizations during update process, this make take a few minutes, please be patient" -l notice
7272

7373
DATABASE=$(sudo -u pioreactor -i pio config get storage database)
7474

0 commit comments

Comments
 (0)