Skip to content

Commit a66bf29

Browse files
authored
Merge branch 'master' into replication-monitoring
2 parents 8b471d8 + f89f00c commit a66bf29

File tree

11 files changed

+135
-31
lines changed

11 files changed

+135
-31
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ jobs:
2121
with:
2222
ignore_words_list: datas
2323
- name: Set up Python ${{ env.PYTHON_DEFAULT_VERSION }}
24-
uses: actions/setup-python@v2
24+
uses: actions/setup-python@v3
2525
with:
2626
python-version: ${{ env.PYTHON_DEFAULT_VERSION }}
27+
cache: "pip"
2728
- name: Install dependencies
2829
run: python -m pip install --upgrade nox pip setuptools
2930
- name: Run linters
@@ -41,9 +42,10 @@ jobs:
4142
with:
4243
fetch-depth: 0
4344
- name: Set up Python ${{ env.PYTHON_DEFAULT_VERSION }}
44-
uses: actions/setup-python@v2
45+
uses: actions/setup-python@v3
4546
with:
4647
python-version: ${{ env.PYTHON_DEFAULT_VERSION }}
48+
cache: "pip"
4749
- name: Install dependencies
4850
run: python -m pip install --upgrade nox pip setuptools
4951
- name: Build the distribution
@@ -61,9 +63,10 @@ jobs:
6163
fetch-depth: 0
6264
- name: Set up Python ${{ env.PYTHON_DEFAULT_VERSION }}
6365
if: ${{ env.B2_TEST_APPLICATION_KEY != '' && env.B2_TEST_APPLICATION_KEY_ID != '' }} # TODO: skip this whole job instead
64-
uses: actions/setup-python@v2
66+
uses: actions/setup-python@v3
6567
with:
6668
python-version: ${{ env.PYTHON_DEFAULT_VERSION }}
69+
cache: "pip"
6770
- name: Install dependencies
6871
if: ${{ env.B2_TEST_APPLICATION_KEY != '' && env.B2_TEST_APPLICATION_KEY_ID != '' }} # TODO: skip this whole job instead
6972
run: python -m pip install --upgrade nox pip setuptools
@@ -95,9 +98,10 @@ jobs:
9598
with:
9699
fetch-depth: 0
97100
- name: Set up Python ${{ matrix.python-version }}
98-
uses: actions/setup-python@v2
101+
uses: actions/setup-python@v3
99102
with:
100103
python-version: ${{ matrix.python-version }}
104+
cache: "pip"
101105
- name: Install dependencies
102106
run: python -m pip install --upgrade nox pip setuptools
103107
- name: Run unit tests
@@ -115,9 +119,10 @@ jobs:
115119
with:
116120
fetch-depth: 0
117121
- name: Set up Python ${{ env.PYTHON_DEFAULT_VERSION }}
118-
uses: actions/setup-python@v2
122+
uses: actions/setup-python@v3
119123
with:
120124
python-version: ${{ env.PYTHON_DEFAULT_VERSION }}
125+
cache: "pip"
121126
- name: Install dependencies
122127
env:
123128
DEBIAN_FRONTEND: noninteractive

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,26 @@ though no known major changes to it are planned at this point. Early adopters ma
1111
feasible to rely this implementation already.
1212

1313
### Added
14+
* Add included_sources module, for keeping track of included modified third-party libraries
1415
* Add `include_existing_files` parameter to `ReplicationSetupHelper`
1516

1617
### Changed
18+
* Change the per part retry limit from 5 to 20 for data transfer operations. Please note that the retry system is not considered to be a part of the public interface and is subject to be adjusted
19+
* Do not wait more than 64 seconds between retry attempts (unless server asks for it)
20+
* On longer failures wait an additional (random, up to 1s) amount of time to prevent client synchronization
21+
* Flatten `ReplicationConfiguration` interface
1722
* Reorder actions of `ReplicationSetupHelper` to avoid zombie rules
1823

1924
### Fixed
2025
* Fix `AccountInfo.is_master_key()`
2126
* Fix docstring of `SqliteAccountInfo`
27+
* Fix lifecycle rule type in the docs
2228

2329
### Infrastructure
2430
* Add 3.11.0-beta.1 to CI
2531
* Change Sphinx major version from 5 to 6
26-
* Extracted folder/bucket scanning into a new `scan` module
27-
* The interface of `ReplicationConfiguration` was flattened
32+
* Extract folder/bucket scanning into a new `scan` module
33+
* Enable pip cache in CI
2834

2935
## [1.16.0] - 2022-04-27
3036

b2sdk/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE

b2sdk/_v3/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@
222222

223223
# other
224224

225+
from b2sdk.included_sources import get_included_sources
225226
from b2sdk.b2http import B2Http
226227
from b2sdk.api_config import B2HttpApiConfig
227228
from b2sdk.api_config import DEFAULT_HTTP_API_CONFIG

b2sdk/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def create_bucket(
221221
:param str bucket_type: a bucket type, could be one of the following values: ``"allPublic"``, ``"allPrivate"``
222222
:param dict bucket_info: additional bucket info to store with the bucket
223223
:param dict cors_rules: bucket CORS rules to store with the bucket
224-
:param dict lifecycle_rules: bucket lifecycle rules to store with the bucket
224+
:param list lifecycle_rules: bucket lifecycle rules to store with the bucket
225225
:param b2sdk.v2.EncryptionSetting default_server_side_encryption: default server side encryption settings (``None`` if unknown)
226226
:param bool is_file_lock_enabled: boolean value specifies whether bucket is File Lock-enabled
227227
:param b2sdk.v2.ReplicationConfiguration replication: bucket replication rules or ``None``

b2sdk/b2http.py

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#
99
######################################################################
1010

11+
from random import random
1112
import io
1213
import json
1314
import logging
@@ -17,7 +18,7 @@
1718
import requests
1819
import time
1920

20-
from typing import Any, Dict
21+
from typing import Any, Dict, Optional
2122

2223
from .exception import (
2324
B2Error, B2RequestTimeoutDuringUpload, BadDateFormat, BrokenPipe, B2ConnectionError,
@@ -151,10 +152,17 @@ class B2Http:
151152
except B2Error as e:
152153
...
153154
155+
Please note that the timeout/retry system, including class-level variables,
156+
is not a part of the interface and is subject to change.
154157
"""
155158

156-
# timeout for HTTP GET/POST requests
157-
TIMEOUT = 1200 # 20 minutes as server-side copy can take time
159+
TIMEOUT = 128
160+
TIMEOUT_FOR_COPY = 1200 # 20 minutes as server-side copy can take time
161+
TIMEOUT_FOR_UPLOAD = 128
162+
TRY_COUNT_DATA = 20
163+
TRY_COUNT_DOWNLOAD = 20
164+
TRY_COUNT_HEAD = 5
165+
TRY_COUNT_OTHER = 5
158166

159167
def __init__(self, api_config: B2HttpApiConfig = DEFAULT_HTTP_API_CONFIG):
160168
"""
@@ -176,7 +184,15 @@ def add_callback(self, callback):
176184
"""
177185
self.callbacks.append(callback)
178186

179-
def post_content_return_json(self, url, headers, data, try_count=5, post_params=None):
187+
def post_content_return_json(
188+
self,
189+
url,
190+
headers,
191+
data,
192+
try_count: int = TRY_COUNT_DATA,
193+
post_params=None,
194+
_timeout: Optional[int] = None,
195+
):
180196
"""
181197
Use like this:
182198
@@ -202,7 +218,10 @@ def do_post():
202218
data.seek(0)
203219
self._run_pre_request_hooks('POST', url, request_headers)
204220
response = self.session.post(
205-
url, headers=request_headers, data=data, timeout=self.TIMEOUT
221+
url,
222+
headers=request_headers,
223+
data=data,
224+
timeout=_timeout or self.TIMEOUT_FOR_UPLOAD,
206225
)
207226
self._run_post_request_hooks('POST', url, request_headers, response)
208227
return response
@@ -223,7 +242,7 @@ def do_post():
223242
finally:
224243
response.close()
225244

226-
def post_json_return_json(self, url, headers, params, try_count=5):
245+
def post_json_return_json(self, url, headers, params, try_count: int = TRY_COUNT_OTHER):
227246
"""
228247
Use like this:
229248
@@ -241,10 +260,24 @@ def post_json_return_json(self, url, headers, params, try_count=5):
241260
:return: the decoded JSON document
242261
:rtype: dict
243262
"""
263+
264+
# This is not just b2_copy_file or b2_copy_part, but it would not
265+
# be good to find out by analyzing the url.
266+
# In the future a more generic system between raw_api and b2http
267+
# to indicate the timeouts should be designed.
268+
timeout = self.TIMEOUT_FOR_COPY
269+
244270
data = io.BytesIO(json.dumps(params).encode())
245-
return self.post_content_return_json(url, headers, data, try_count, params)
271+
return self.post_content_return_json(
272+
url,
273+
headers,
274+
data,
275+
try_count,
276+
params,
277+
_timeout=timeout,
278+
)
246279

247-
def get_content(self, url, headers, try_count=5):
280+
def get_content(self, url, headers, try_count: int = TRY_COUNT_DOWNLOAD):
248281
"""
249282
Fetches content from a URL.
250283
@@ -282,7 +315,12 @@ def do_get():
282315
response = self._translate_and_retry(do_get, try_count, None)
283316
return ResponseContextManager(response)
284317

285-
def head_content(self, url: str, headers: Dict[str, Any], try_count: int = 5) -> Dict[str, Any]:
318+
def head_content(
319+
self,
320+
url: str,
321+
headers: Dict[str, Any],
322+
try_count: int = TRY_COUNT_HEAD,
323+
) -> Dict[str, Any]:
286324
"""
287325
Does a HEAD instead of a GET for the URL.
288326
The response's content is limited to the headers.
@@ -413,6 +451,7 @@ def _translate_and_retry(cls, fcn, try_count, post_params=None):
413451
"""
414452
# For all but the last try, catch the exception.
415453
wait_time = 1.0
454+
max_wait_time = 64
416455
for _ in range(try_count - 1):
417456
try:
418457
return cls._translate_errors(fcn, post_params)
@@ -426,11 +465,20 @@ def _translate_and_retry(cls, fcn, try_count, post_params=None):
426465
else:
427466
sleep_duration = wait_time
428467
sleep_reason = 'that is what the default exponential backoff is'
468+
429469
logger.info(
430-
'Pausing thread for %i seconds because %s', sleep_duration, sleep_reason
470+
'Pausing thread for %i seconds because %s',
471+
sleep_duration,
472+
sleep_reason,
431473
)
432474
time.sleep(sleep_duration)
475+
476+
# Set up wait time for the next iteration
433477
wait_time *= 1.5
478+
if wait_time > max_wait_time:
479+
# avoid clients synchronizing and causing a wave
480+
# of requests when connectivity is restored
481+
wait_time = max_wait_time + random()
434482

435483
# If the last try gets an exception, it will be raised.
436484
return cls._translate_errors(fcn, post_params)

b2sdk/bucket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def __init__(
8181
:param str type_: a bucket type
8282
:param dict bucket_info: an info to store with a bucket
8383
:param dict cors_rules: CORS rules to store with a bucket
84-
:param dict lifecycle_rules: lifecycle rules to store with a bucket
84+
:param list lifecycle_rules: lifecycle rules of the bucket
8585
:param int revision: a bucket revision number
8686
:param dict bucket_dict: a dictionary which contains bucket parameters
8787
:param set options_set: set of bucket options strings
@@ -145,7 +145,7 @@ def update(
145145
bucket_type: Optional[str] = None,
146146
bucket_info: Optional[dict] = None,
147147
cors_rules: Optional[dict] = None,
148-
lifecycle_rules: Optional[dict] = None,
148+
lifecycle_rules: Optional[list] = None,
149149
if_revision_is: Optional[int] = None,
150150
default_server_side_encryption: Optional[EncryptionSetting] = None,
151151
default_retention: Optional[BucketRetentionSetting] = None,

b2sdk/included_sources.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
######################################################################
2+
#
3+
# File: b2sdk/included_sources.py
4+
#
5+
# Copyright 2021 Backblaze Inc. All Rights Reserved.
6+
#
7+
# License https://www.backblaze.com/using_b2_code.html
8+
#
9+
######################################################################
10+
11+
# This module provides a list of third party sources included and modified in b2sdk, so it can be exposed to
12+
# B2 Command Line Tool for printing, for legal compliance reasons
13+
14+
import dataclasses
15+
from typing import Dict, List
16+
17+
_included_sources: List['IncludedSourceMeta'] = []
18+
19+
20+
@dataclasses.dataclass
21+
class IncludedSourceMeta:
22+
name: str
23+
comment: str
24+
files: Dict[str, str]
25+
26+
27+
def add_included_source(src: IncludedSourceMeta):
28+
_included_sources.append(src)
29+
30+
31+
def get_included_sources() -> List['IncludedSourceMeta']:
32+
return _included_sources

b2sdk/v1/bucket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def update(
205205
bucket_type: Optional[str] = None,
206206
bucket_info: Optional[dict] = None,
207207
cors_rules: Optional[dict] = None,
208-
lifecycle_rules: Optional[dict] = None,
208+
lifecycle_rules: Optional[list] = None,
209209
if_revision_is: Optional[int] = None,
210210
default_server_side_encryption: Optional[v2.EncryptionSetting] = None,
211211
default_retention: Optional[v2.BucketRetentionSetting] = None,
@@ -217,7 +217,7 @@ def update(
217217
:param bucket_type: a bucket type, e.g. ``allPrivate`` or ``allPublic``
218218
:param bucket_info: an info to store with a bucket
219219
:param cors_rules: CORS rules to store with a bucket
220-
:param lifecycle_rules: lifecycle rules to store with a bucket
220+
:param lifecycle_rules: lifecycle rules of the bucket
221221
:param if_revision_is: revision number, update the info **only if** *revision* equals to *if_revision_is*
222222
:param default_server_side_encryption: default server side encryption settings (``None`` if unknown)
223223
:param default_retention: bucket default retention setting

test/integration/test_raw_api.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,12 @@ def raw_api_test_helper(raw_api, should_cleanup_old_buckets):
153153
api_url,
154154
account_auth_token,
155155
account_id,
156-
['listBuckets', 'listFiles', 'readFiles', 'writeFiles'],
156+
[
157+
'listBuckets',
158+
'listFiles',
159+
'readFiles',
160+
'writeFiles', # Pawel @ 2022-06-21: adding this to make tests pass with a weird server validator
161+
],
157162
'testReplicationSourceKey',
158163
None,
159164
None,

0 commit comments

Comments
 (0)