Skip to content

Commit 6e7d56a

Browse files
committed
Improve handling of download concurrency
Don't save download concurrency defaults in the database. Make it easier for individual plugins to override. closes: #8897 https://pulp.plan.io/issues/8897
1 parent 282b6a5 commit 6e7d56a

8 files changed

Lines changed: 43 additions & 9 deletions

File tree

CHANGES/8897.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The default ``download_concurrency`` of 10 was found to be too high for many client types, it has been reduced to 8. Additionally, where before ``download_concurrency`` would be set to a default value upon creation, it will now be set NULL (but a default value will still be used).

CHANGES/plugin_api/8897.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added a field ``DEFAULT_DOWNLOAD_CONCURRENCY`` to the Remote base class - plugin writers can override the number of concurrent downloads for each type of remote. The default value is 8.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 2.2.24 on 2021-06-13 03:14
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('core', '0065_merge_20210615_1211'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='remote',
16+
name='download_concurrency',
17+
field=models.PositiveIntegerField(null=True, validators=[django.core.validators.MinValueValidator(1)]),
18+
),
19+
]

pulpcore/app/models/repository.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ class Remote(MasterModel):
256256
ON_DEMAND = "on_demand"
257257
STREAMED = "streamed"
258258

259+
DEFAULT_DOWNLOAD_CONCURRENCY = 8
260+
259261
POLICY_CHOICES = (
260262
(IMMEDIATE, "When syncing, download all metadata and content now."),
261263
(
@@ -288,7 +290,7 @@ class Remote(MasterModel):
288290
proxy_username = models.TextField(null=True)
289291
proxy_password = models.TextField(null=True)
290292

291-
download_concurrency = models.PositiveIntegerField(default=10)
293+
download_concurrency = models.PositiveIntegerField(null=True, validators=[MinValueValidator(1)])
292294
policy = models.TextField(choices=POLICY_CHOICES, default=IMMEDIATE)
293295

294296
total_timeout = models.FloatField(
@@ -323,7 +325,10 @@ def download_factory(self):
323325
try:
324326
return self._download_factory
325327
except AttributeError:
326-
self._download_factory = DownloaderFactory(self)
328+
# if a download concurrency value was not provided (0), then use the default
329+
# concurrency, which can be overridden on a per-remote-type basis.
330+
concurrency = self.download_concurrency or self.DEFAULT_DOWNLOAD_CONCURRENCY
331+
self._download_factory = DownloaderFactory(self, download_concurrency=concurrency)
327332
return self._download_factory
328333

329334
@property

pulpcore/app/serializers/repository.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,13 @@ class RemoteSerializer(ModelSerializer):
136136
help_text="Timestamp of the most recent update of the remote.", read_only=True
137137
)
138138
download_concurrency = serializers.IntegerField(
139-
help_text="Total number of simultaneous connections.", required=False, min_value=1
139+
help_text=(
140+
"Total number of simultaneous connections. If not provided or set to zero (0), "
141+
"then the default value will be used."
142+
),
143+
allow_null=True,
144+
required=False,
145+
min_value=1,
140146
)
141147
policy = serializers.ChoiceField(
142148
help_text="The policy to use when downloading content.",

pulpcore/download/factory.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,17 @@ class DownloaderFactory:
6565
to session continuation implementation in various servers.
6666
"""
6767

68-
def __init__(self, remote, downloader_overrides=None):
68+
def __init__(self, remote, downloader_overrides=None, download_concurrency=None):
6969
"""
7070
Args:
7171
remote (:class:`~pulpcore.plugin.models.Remote`): The remote used to populate
7272
downloader settings.
7373
downloader_overrides (dict): Keyed on a scheme name, e.g. 'https' or 'ftp' and the value
7474
is the downloader class to be used for that scheme, e.g.
7575
{'https': MyCustomDownloader}. These override the default values.
76+
download_concurrency (int): How many files may be downloaded concurrently.
7677
"""
78+
download_concurrency = download_concurrency or remote.DEFAULT_DOWNLOAD_CONCURRENCY
7779
self._remote = remote
7880
self._download_class_map = copy.copy(PROTOCOL_MAP)
7981
if downloader_overrides:
@@ -85,7 +87,7 @@ def __init__(self, remote, downloader_overrides=None):
8587
"file": self._generic,
8688
}
8789
self._session = self._make_aiohttp_session_from_remote()
88-
self._semaphore = asyncio.Semaphore(value=remote.download_concurrency)
90+
self._semaphore = asyncio.Semaphore(value=download_concurrency)
8991
atexit.register(self._session_cleanup)
9092

9193
def _session_cleanup(self):

pulpcore/download/http.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ async def _run(self, extra_data=None):
201201
"""
202202
Download, validate, and compute digests on the `url`. This is a coroutine.
203203
204-
This method is decorated with a backoff-and-retry behavior to retry HTTP 429 and
205-
some 5XX errors. It retries with exponential backoff 10 times before allowing
206-
a final exception to be raised.
204+
This method is decorated with a backoff-and-retry behavior to retry some errors.
205+
It retries with exponential backoff 10 times before allowing a final exception to
206+
be raised.
207207
208208
This method provides the same return object type and documented in
209209
:meth:`~pulpcore.plugin.download.BaseDownloader._run`.

pulpcore/tests/functional/api/using_plugin/test_crud_repos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def test_read(self):
254254
self._compare_results(self.remote_attrs, self.remote)
255255

256256
def test_update(self):
257-
data = {"download_concurrency": 66, "policy": "immediate"}
257+
data = {"download_concurrency": 23, "policy": "immediate"}
258258
self.remotes_api.partial_update(self.remote.pulp_href, data)
259259
time.sleep(1) # without this, the read returns the pre-patch values
260260
new_remote = self.remotes_api.read(self.remote.pulp_href)

0 commit comments

Comments
 (0)