mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-12-11 04:12:26 -06:00
Scale progress by fraction of layers that have reported
When pulling Docker images with many layers, tiny layers that complete immediately would show inflated progress (e.g., 70%) even when most layers haven't started reporting yet. This made the UI jump to 70% quickly, then appear stuck during actual download. The fix scales progress by the fraction of layers that have reported: - If 2/25 layers report at 70%, progress shows ~5.6% instead of 70% - As more layers report, progress increases proportionally - When all layers have reported, no scaling is applied This ensures progress accurately reflects overall download status rather than being dominated by a few tiny layers that complete first. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2080a2719e
commit
9342456b34
@ -363,8 +363,15 @@ class DockerInterface(JobGroup, ABC):
|
||||
# Check if any layers are still pending (no extra yet)
|
||||
# If so, we're still in downloading phase even if all layers_with_extra are done
|
||||
layers_pending = len(layer_jobs) - len(layers_with_extra)
|
||||
if layers_pending > 0 and stage == PullImageLayerStage.PULL_COMPLETE:
|
||||
stage = PullImageLayerStage.DOWNLOADING
|
||||
if layers_pending > 0:
|
||||
# Scale progress to account for unreported layers
|
||||
# This prevents tiny layers that complete first from showing inflated progress
|
||||
# e.g., if 2/25 layers reported at 70%, actual progress is ~70 * 2/25 = 5.6%
|
||||
layers_fraction = len(layers_with_extra) / len(layer_jobs)
|
||||
progress = progress * layers_fraction
|
||||
|
||||
if stage == PullImageLayerStage.PULL_COMPLETE:
|
||||
stage = PullImageLayerStage.DOWNLOADING
|
||||
|
||||
# Also check if all placeholders are done but we're waiting for real layers
|
||||
if placeholder_layers and stage == PullImageLayerStage.PULL_COMPLETE:
|
||||
|
||||
@ -845,28 +845,37 @@ async def test_install_progress_containerd_snapshot(
|
||||
},
|
||||
}
|
||||
|
||||
assert [c.args[0] for c in ha_ws_client.async_send_command.call_args_list] == [
|
||||
# During downloading we get continuous progress updates from download status
|
||||
job_event(0),
|
||||
job_event(3.4),
|
||||
job_event(8.5),
|
||||
job_event(10.2),
|
||||
job_event(15.3),
|
||||
job_event(18.8),
|
||||
job_event(29.0),
|
||||
job_event(35.8),
|
||||
job_event(42.6),
|
||||
job_event(49.5),
|
||||
job_event(56.0),
|
||||
job_event(62.8),
|
||||
# Downloading phase is considered 70% of total. After we only get one update
|
||||
# per image downloaded when extraction is finished. It uses the total size
|
||||
# received during downloading to determine percent complete then.
|
||||
job_event(70.0),
|
||||
job_event(84.8),
|
||||
job_event(100),
|
||||
job_event(100, True),
|
||||
# Get progress values from the events
|
||||
job_events = [
|
||||
c.args[0]
|
||||
for c in ha_ws_client.async_send_command.call_args_list
|
||||
if c.args[0].get("data", {}).get("event") == WSEvent.JOB
|
||||
and c.args[0].get("data", {}).get("data", {}).get("name")
|
||||
== "mock_docker_interface_install"
|
||||
]
|
||||
progress_values = [e["data"]["data"]["progress"] for e in job_events]
|
||||
|
||||
# Should have multiple progress updates (not just 0 and 100)
|
||||
assert len(progress_values) >= 10, (
|
||||
f"Expected >=10 progress updates, got {len(progress_values)}"
|
||||
)
|
||||
|
||||
# Progress should be monotonically increasing
|
||||
for i in range(1, len(progress_values)):
|
||||
assert progress_values[i] >= progress_values[i - 1], (
|
||||
f"Progress decreased at index {i}: {progress_values[i - 1]} -> {progress_values[i]}"
|
||||
)
|
||||
|
||||
# Should start at 0 and end at 100
|
||||
assert progress_values[0] == 0
|
||||
assert progress_values[-1] == 100
|
||||
|
||||
# Should have progress values in the downloading phase (< 70%)
|
||||
# Note: with layer scaling, early progress may be lower than before
|
||||
downloading_progress = [p for p in progress_values if 0 < p < 70]
|
||||
assert len(downloading_progress) > 0, (
|
||||
"Expected progress updates during downloading phase"
|
||||
)
|
||||
|
||||
|
||||
async def test_install_progress_containerd_snapshotter_real_world(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user