Skip to content

Commit 7cb52b1

Browse files
authored
Merge pull request #289 from scieloorg/codex/configurable-objectstore-timeout
Make objectstore timeout configurable
2 parents 3780ee4 + 76cb6b3 commit 7cb52b1

3 files changed

Lines changed: 64 additions & 10 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ https://docs.mongodb.com/master/core/transactions/.
7777
Configurações avançadas:
7878

7979

80-
variável de ambiente | valor padrão
81-
--------------------------|-------------
82-
KERNEL_LIB_MAX_RETRIES | 4
83-
KERNEL_LIB_BACKOFF_FACTOR | 1.2
80+
variável de ambiente | valor padrão
81+
-------------------------------|-------------
82+
KERNEL_LIB_MAX_RETRIES | 4
83+
KERNEL_LIB_BACKOFF_FACTOR | 1.2
84+
KERNEL_LIB_OBJECTSTORE_TIMEOUT | 2
8485

8586
### Executando via código-fonte e Pip:
8687

documentstore/domain.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
MAX_RETRIES = int(os.environ.get("KERNEL_LIB_MAX_RETRIES", "4"))
4343
BACKOFF_FACTOR = float(os.environ.get("KERNEL_LIB_BACKOFF_FACTOR", "1.2"))
44+
OBJECTSTORE_TIMEOUT = float(os.environ.get("KERNEL_LIB_OBJECTSTORE_TIMEOUT", "2"))
4445
OBJECTSTORE_RESPONSE_TIME_SECONDS = Summary(
4546
"kernel_objectstore_response_time_seconds",
4647
"Elapsed time between the request for an XML and the response",
@@ -55,6 +56,14 @@ def utcnow():
5556
return str(datetime.utcnow().isoformat() + "Z")
5657

5758

59+
def objectstore_timeout(timeout=None):
60+
if timeout is None:
61+
return float(
62+
os.environ.get("KERNEL_LIB_OBJECTSTORE_TIMEOUT", OBJECTSTORE_TIMEOUT)
63+
)
64+
return timeout
65+
66+
5867
class DocumentManifest:
5968
"""Namespace para funções que manipulam o manifesto do documento.
6069
"""
@@ -231,7 +240,8 @@ def wrapper(*args, **kwargs):
231240
@retry_gracefully()
232241
@OBJECTSTORE_REQUEST_FAILURES_TOTAL.count_exceptions()
233242
@OBJECTSTORE_RESPONSE_TIME_SECONDS.time()
234-
def fetch_data(url: str, timeout: float = 2) -> bytes:
243+
def fetch_data(url: str, timeout: float = None) -> bytes:
244+
timeout = objectstore_timeout(timeout)
235245
try:
236246
response = requests.get(url, timeout=timeout)
237247
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as exc:
@@ -257,7 +267,7 @@ def fetch_data(url: str, timeout: float = 2) -> bytes:
257267

258268

259269
def assets_from_remote_xml(
260-
url: str, timeout: float = 2, parser=DEFAULT_XMLPARSER
270+
url: str, timeout: float = None, parser=DEFAULT_XMLPARSER
261271
) -> list:
262272
data = fetch_data(url, timeout)
263273
xml = etree.parse(BytesIO(data), parser)
@@ -350,7 +360,11 @@ def id(self):
350360
return self.manifest.get("id", "")
351361

352362
def new_version(
353-
self, data_url, assets_getter=assets_from_remote_xml, timeout=2, ensure_unique_name=False
363+
self,
364+
data_url,
365+
assets_getter=assets_from_remote_xml,
366+
timeout=None,
367+
ensure_unique_name=False,
354368
) -> None:
355369
"""Adiciona `data_url` como uma nova versão do documento.
356370
@@ -371,7 +385,7 @@ def new_version(
371385
"could not add version: the version is equal to the latest one"
372386
)
373387

374-
_, data_assets = assets_getter(data_url, timeout=timeout)
388+
_, data_assets = assets_getter(data_url, timeout=objectstore_timeout(timeout))
375389
data_assets_keys = [asset_key for asset_key, _ in data_assets]
376390
assets = self._link_assets(data_assets_keys)
377391
self.manifest = DocumentManifest.add_version(
@@ -500,7 +514,7 @@ def data(
500514
version_index=-1,
501515
version_at=None,
502516
assets_getter=assets_from_remote_xml,
503-
timeout=2,
517+
timeout=None,
504518
) -> bytes:
505519
"""Retorna o conteúdo do XML, codificado em UTF-8, já com as
506520
referências aos ativos digitais correspondendo às da versão solicitada.
@@ -526,7 +540,9 @@ def data(
526540
raise exceptions.DeletedVersion(
527541
"cannot get data: the document was deleted")
528542

529-
xml_tree, data_assets = assets_getter(version["data"], timeout=timeout)
543+
xml_tree, data_assets = assets_getter(
544+
version["data"], timeout=objectstore_timeout(timeout)
545+
)
530546

531547
version_assets = version["assets"]
532548
for asset_key, target_node in data_assets:

tests/test_domain.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,43 @@ def test_sleep_increases_exponentially(self):
20262026
retry_gracefully._sleep.assert_has_calls(calls)
20272027

20282028

2029+
class ObjectstoreTimeoutTests(unittest.TestCase):
2030+
def test_default_timeout_value(self):
2031+
with mock.patch.dict(domain.os.environ, {}, clear=True):
2032+
self.assertEqual(domain.objectstore_timeout(), 2)
2033+
2034+
def test_timeout_value_from_environment(self):
2035+
with mock.patch.dict(
2036+
domain.os.environ, {"KERNEL_LIB_OBJECTSTORE_TIMEOUT": "15.5"}
2037+
):
2038+
self.assertEqual(domain.objectstore_timeout(), 15.5)
2039+
2040+
def test_explicit_timeout_value_has_priority(self):
2041+
with mock.patch.dict(
2042+
domain.os.environ, {"KERNEL_LIB_OBJECTSTORE_TIMEOUT": "15.5"}
2043+
):
2044+
self.assertEqual(domain.objectstore_timeout(3), 3)
2045+
2046+
def test_fetch_data_uses_configured_timeout(self):
2047+
response = mock.Mock()
2048+
response.content = b"<article/>"
2049+
response.raise_for_status.return_value = None
2050+
2051+
with mock.patch.dict(
2052+
domain.os.environ, {"KERNEL_LIB_OBJECTSTORE_TIMEOUT": "15.5"}
2053+
):
2054+
with mock.patch(
2055+
"documentstore.domain.requests.get", return_value=response
2056+
) as request_get:
2057+
self.assertEqual(
2058+
domain.fetch_data("https://example.org/doc.xml"), b"<article/>"
2059+
)
2060+
2061+
request_get.assert_called_once_with(
2062+
"https://example.org/doc.xml", timeout=15.5
2063+
)
2064+
2065+
20292066
class MetadataWithStylesForArticleWithTransTitlesTests(unittest.TestCase):
20302067

20312068
def setUp(self):

0 commit comments

Comments
 (0)