Skip to content

Commit 338a669

Browse files
author
Andrei Neagu
committed
added attempts
1 parent 1abd071 commit 338a669

File tree

4 files changed

+59
-49
lines changed

4 files changed

+59
-49
lines changed

packages/models-library/src/models_library/progress_bar.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
from pydantic import BaseModel, ConfigDict
44

5-
from .basic_types import IDStr
6-
75
# NOTE: keep a list of possible unit, and please use correct official unit names
86
ProgressUnit: TypeAlias = Literal["Byte"]
97

108

119
class ProgressStructuredMessage(BaseModel):
12-
description: IDStr
10+
description: str
1311
current: float
1412
total: int
1513
unit: str | None = None
@@ -51,6 +49,7 @@ class ProgressStructuredMessage(BaseModel):
5149
class ProgressReport(BaseModel):
5250
actual_value: float
5351
total: float = 1.0
52+
attempt: int = 0
5453
unit: ProgressUnit | None = UNITLESS
5554
message: ProgressStructuredMessage | None = None
5655

packages/service-library/src/servicelib/docker_utils.py

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
)
2323
from settings_library.docker_registry import RegistrySettings
2424
from tenacity import (
25-
AsyncRetrying,
25+
retry,
2626
retry_if_exception_type,
2727
stop_after_attempt,
2828
wait_random_exponential,
@@ -237,6 +237,7 @@ async def pull_image(
237237
image_information -- the image layer information. If this is None, then no fine progress will be retrieved.
238238
retry_upon_error_count -- number of tries if there is a TimeoutError. Usually cased by networking issues.
239239
"""
240+
240241
registry_auth = None
241242
if registry_settings.REGISTRY_URL and registry_settings.REGISTRY_URL in image:
242243
registry_auth = {
@@ -262,56 +263,59 @@ async def pull_image(
262263

263264
client = await exit_stack.enter_async_context(aiodocker.Docker())
264265

265-
async for attempt in AsyncRetrying(
266+
def _reset_progress_from_previous_attempt() -> None:
267+
for pulled_status in layer_id_to_size.values():
268+
pulled_status.downloaded = 0
269+
pulled_status.extracted = 0
270+
271+
@retry(
266272
wait=wait_random_exponential(),
267273
stop=stop_after_attempt(retry_upon_error_count),
268274
reraise=True,
269275
retry=retry_if_exception_type(asyncio.TimeoutError),
270-
):
271-
# each time there is an error progress starts from zero
276+
)
277+
async def _pull_image_with_retry() -> None:
278+
# for each attempt rest the progress
272279
progress_bar.reset_progress()
273-
_logger.info(
274-
"attempt='%s' to pull image='%s'",
275-
attempt.retry_state.attempt_number,
276-
image,
277-
)
280+
_reset_progress_from_previous_attempt()
281+
282+
_logger.info("trying to pull image='%s'", image)
278283

279-
with attempt:
280-
reported_progress = 0.0
281-
async for pull_progress in client.images.pull(
282-
image, stream=True, auth=registry_auth
283-
):
284-
try:
285-
parsed_progress = TypeAdapter(_DockerPullImage).validate_python(
286-
pull_progress
287-
)
288-
except ValidationError:
289-
_logger.exception(
290-
"Unexpected error while validating '%s'. "
291-
"TIP: This is probably an unforeseen pull status text that shall be added to the code. "
292-
"The pulling process will still continue.",
293-
f"{pull_progress=}",
294-
)
295-
else:
296-
await _parse_pull_information(
297-
parsed_progress, layer_id_to_size=layer_id_to_size
298-
)
299-
300-
# compute total progress
301-
total_downloaded_size = sum(
302-
layer.downloaded for layer in layer_id_to_size.values()
284+
reported_progress = 0.0
285+
async for pull_progress in client.images.pull(
286+
image, stream=True, auth=registry_auth
287+
):
288+
try:
289+
parsed_progress = TypeAdapter(_DockerPullImage).validate_python(
290+
pull_progress
303291
)
304-
total_extracted_size = sum(
305-
layer.extracted for layer in layer_id_to_size.values()
292+
except ValidationError:
293+
_logger.exception(
294+
"Unexpected error while validating '%s'. "
295+
"TIP: This is probably an unforeseen pull status text that shall be added to the code. "
296+
"The pulling process will still continue.",
297+
f"{pull_progress=}",
306298
)
307-
total_progress = (
308-
total_downloaded_size + total_extracted_size
309-
) / 2.0
310-
progress_to_report = total_progress - reported_progress
311-
await progress_bar.update(progress_to_report)
312-
reported_progress = total_progress
313-
314-
await log_cb(
315-
f"pulling {image_short_name}: {pull_progress}...",
316-
logging.DEBUG,
299+
else:
300+
await _parse_pull_information(
301+
parsed_progress, layer_id_to_size=layer_id_to_size
317302
)
303+
304+
# compute total progress
305+
total_downloaded_size = sum(
306+
layer.downloaded for layer in layer_id_to_size.values()
307+
)
308+
total_extracted_size = sum(
309+
layer.extracted for layer in layer_id_to_size.values()
310+
)
311+
total_progress = (total_downloaded_size + total_extracted_size) / 2.0
312+
progress_to_report = total_progress - reported_progress
313+
await progress_bar.update(progress_to_report)
314+
reported_progress = total_progress
315+
316+
await log_cb(
317+
f"pulling {image_short_name}: {pull_progress}...",
318+
logging.DEBUG,
319+
)
320+
321+
await _pull_image_with_retry()

packages/service-library/src/servicelib/progress_bar.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ async def main_fct():
8787
progress_unit: ProgressUnit | None = None
8888
progress_report_cb: AsyncReportCB | ReportCB | None = None
8989
_current_steps: float = _INITIAL_VALUE
90+
_currnet_attempt: int = 0
9091
_children: list["ProgressBarData"] = field(default_factory=list)
9192
_parent: Optional["ProgressBarData"] = None
9293
_continuous_value_lock: asyncio.Lock = field(init=False)
@@ -146,6 +147,7 @@ async def _report_external(self, value: float) -> None:
146147
# NOTE: here we convert back to actual value since this is possibly weighted
147148
actual_value=value * self.num_steps,
148149
total=self.num_steps,
150+
attempt=self._currnet_attempt,
149151
unit=self.progress_unit,
150152
message=self.compute_report_message_stuct(),
151153
),
@@ -197,7 +199,9 @@ async def update(self, steps: float = 1) -> None:
197199
await self._report_external(new_progress_value)
198200

199201
def reset_progress(self) -> None:
202+
self._currnet_attempt += 1
200203
self._current_steps = _INITIAL_VALUE
204+
self._last_report_value = _INITIAL_VALUE
201205

202206
async def set_(self, new_value: float) -> None:
203207
await self.update(new_value - self._current_steps)

services/static-webserver/client/source/class/osparc/data/model/NodeProgressSequence.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,11 @@ qx.Class.define("osparc.data.model.NodeProgressSequence", {
186186

187187
getProgress: function(report) {
188188
if (report.unit) {
189+
const attempt = ("attempt" in report && report["attempt"] > 1) ? `(attempt ${report["attempt"]}) ` : "";
190+
const current_value = osparc.utils.Utils.bytesToSize(report["actual_value"], 1, false);
191+
const total_value = osparc.utils.Utils.bytesToSize(report["total"], 1, false)
189192
return {
190-
progressLabel: `${osparc.utils.Utils.bytesToSize(report["actual_value"], 1, false)} / ${osparc.utils.Utils.bytesToSize(report["total"], 1, false)}`,
193+
progressLabel: `${attempt}${current_value} / ${total_value}`,
191194
value: report["actual_value"] / report["total"]
192195
}
193196
}

0 commit comments

Comments
 (0)