Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,42 @@ Advanced publishing configuration

.. versionadded:: 2.5

.. _confluence_publish_retry_attempts:

.. confval:: confluence_publish_retry_attempts

Allows a user to override how many retry attempts are permitted when a
single API request fails. By default, this extension uses a maximum
retry of two, allowing a single request to be attempted three times
for select failure events.

Failure scenarios that are retried on include all 500-series errors,
as well as couple of observed/reported corner cases reported by
Confluence instances during the life-cycle of this extension.

.. code-block:: python

confluence_publish_retry_attempts = 2

See also :lref:`confluence_publish_retry_duration`.

.. versionadded:: 2.10

.. _confluence_publish_retry_duration:

.. confval:: confluence_publish_retry_duration

The duration (in seconds) to wait between API retry events on select
failures. By default, the duration waited is four seconds.

.. code-block:: python

confluence_publish_retry_duration = 4

See also :lref:`confluence_publish_retry_attempts`.

.. versionadded:: 2.10

.. confval:: confluence_request_session_override

A hook to manipulate a Requests_ session prepared by this extension. Allows
Expand Down
4 changes: 4 additions & 0 deletions sphinxcontrib/confluencebuilder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ def setup(app):
cm.add_conf_int('confluence_publish_orphan_container')
# Override the path prefixes for various REST API requests.
cm.add_conf('confluence_publish_override_api_prefix')
# Number of attempts permitted when trying to retry a failed API request
cm.add_conf('confluence_publish_retry_attempts')
# Duration (in seconds) between retrying failed API requests
cm.add_conf('confluence_publish_retry_duration')
# Manipulate a requests instance.
cm.add_conf('confluence_request_session_override')
# Authentication passthrough for Confluence REST interaction.
Expand Down
10 changes: 10 additions & 0 deletions sphinxcontrib/confluencebuilder/config/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,16 @@ def conf_translate(value):

# ##################################################################

validator.conf('confluence_publish_retry_attempts') \
.int_(positive=True)

# ##################################################################

validator.conf('confluence_publish_retry_duration') \
.int_(positive=True)

# ##################################################################

validator.conf('confluence_publish_root') \
.int_(positive=True)

Expand Down
14 changes: 12 additions & 2 deletions sphinxcontrib/confluencebuilder/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,23 @@ def confluence_error_retries():
def _decorator(func):
@wraps(func)
def _wrapper(self, *args, **kwargs):
if self.config.confluence_publish_retry_attempts:
retry_attempts = self.config.confluence_publish_retry_attempts
else:
retry_attempts = REMOTE_ERR_MAX_RETRIES

if self.config.confluence_publish_retry_duration:
retry_duration = self.config.confluence_publish_retry_duration
else:
retry_duration = REMOTE_ERR_MAX_RETRY_DURATION

attempt = 1
while True:
try:
return func(self, *args, **kwargs)
except ConfluenceBadApiError as ex: # noqa: PERF203
# if max attempts have been reached, stop any more attempts
if attempt > REMOTE_ERR_MAX_RETRIES:
if attempt > retry_attempts:
raise

# The following will contain a series of known error
Expand All @@ -124,7 +134,7 @@ def _wrapper(self, *args, **kwargs):
raise

# configure the delay
delay = REMOTE_ERR_MAX_RETRY_DURATION
delay = retry_duration

# add jitter
delay += random.uniform(0.0, 0.5) # noqa: S311
Expand Down
22 changes: 22 additions & 0 deletions tests/unit-tests/test_config_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,28 @@ def test_config_check_publish_prefix(self):
self.config['confluence_publish_prefix'] = 'dummy'
self._try_config()

def test_config_check_publish_retry_attempts(self):
self.config['confluence_publish_retry_attempts'] = 10
self._try_config()

self.config['confluence_publish_retry_attempts'] = '999'
self._try_config()

self.config['confluence_publish_retry_attempts'] = -1
with self.assertRaises(ConfluenceConfigError):
self._try_config()

def test_config_check_publish_retry_duration(self):
self.config['confluence_publish_retry_duration'] = 2
self._try_config()

self.config['confluence_publish_retry_duration'] = '2'
self._try_config()

self.config['confluence_publish_retry_duration'] = -1
with self.assertRaises(ConfluenceConfigError):
self._try_config()

def test_config_check_publish_root(self):
# enable publishing enabled checks
self._prepare_valid_publish()
Expand Down