Skip to content

Commit

Permalink
Attribute error fix for retry policy (#1322)
Browse files Browse the repository at this point in the history
* ModuleNotFound error fix for retry policy

* Flake8 fixes

* Changing modulenotfound to attribute error

---------

Co-authored-by: Gavin Aguiar <gavin@GavinPC>
  • Loading branch information
gavin-aguiar and Gavin Aguiar authored Oct 10, 2023
1 parent 82b988e commit 72ec585
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 28 deletions.
67 changes: 44 additions & 23 deletions azure_functions_worker/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .bindings.retrycontext import RetryPolicy
from .constants import MODULE_NOT_FOUND_TS_URL, SCRIPT_FILE_NAME, \
PYTHON_LANGUAGE_RUNTIME, RETRY_POLICY, CUSTOMER_PACKAGES_PATH
from .logging import logger
from .utils.wrappers import attach_message_to_exception

_AZURE_NAMESPACE = '__app__'
Expand Down Expand Up @@ -66,36 +67,56 @@ def build_binding_protos(indexed_function) -> Dict:


def build_retry_protos(indexed_function) -> Dict:
retry = indexed_function.get_settings_dict(RETRY_POLICY)
retry = get_retry_settings(indexed_function)

if not retry:
return None

strategy = retry.get(RetryPolicy.STRATEGY.value)
max_retry_count = int(retry.get(RetryPolicy.MAX_RETRY_COUNT.value))
retry_strategy = retry.get(RetryPolicy.STRATEGY.value)

if strategy == "fixed_delay":
delay_interval = Duration(
seconds=convert_to_seconds(
retry.get(RetryPolicy.DELAY_INTERVAL.value)))
retry_protos = protos.RpcRetryOptions(
max_retry_count=int(retry.get(RetryPolicy.MAX_RETRY_COUNT.value)),
retry_strategy=retry.get(RetryPolicy.STRATEGY.value),
delay_interval=delay_interval,
)
return build_fixed_delay_retry(retry, max_retry_count, retry_strategy)
else:
minimum_interval = Duration(
seconds=convert_to_seconds(
retry.get(RetryPolicy.MINIMUM_INTERVAL.value)))
maximum_interval = Duration(
seconds=convert_to_seconds(
retry.get(RetryPolicy.MAXIMUM_INTERVAL.value)))

retry_protos = protos.RpcRetryOptions(
max_retry_count=int(retry.get(RetryPolicy.MAX_RETRY_COUNT.value)),
retry_strategy=retry.get(RetryPolicy.STRATEGY.value),
minimum_interval=minimum_interval,
maximum_interval=maximum_interval
)
return build_variable_interval_retry(retry, max_retry_count,
retry_strategy)


def get_retry_settings(indexed_function):
try:
return indexed_function.get_settings_dict(RETRY_POLICY)
except AttributeError as e:
logger.warning("AttributeError while loading retry policy. %s", e)
return None


return retry_protos
def build_fixed_delay_retry(retry, max_retry_count, retry_strategy):
delay_interval = Duration(
seconds=convert_to_seconds(retry.get(RetryPolicy.DELAY_INTERVAL.value))
)
return protos.RpcRetryOptions(
max_retry_count=max_retry_count,
retry_strategy=retry_strategy,
delay_interval=delay_interval,
)


def build_variable_interval_retry(retry, max_retry_count, retry_strategy):
minimum_interval = Duration(
seconds=convert_to_seconds(
retry.get(RetryPolicy.MINIMUM_INTERVAL.value))
)
maximum_interval = Duration(
seconds=convert_to_seconds(
retry.get(RetryPolicy.MAXIMUM_INTERVAL.value))
)
return protos.RpcRetryOptions(
max_retry_count=max_retry_count,
retry_strategy=retry_strategy,
minimum_interval=minimum_interval,
maximum_interval=maximum_interval
)


def process_indexed_function(functions_registry: functions.Registry,
Expand Down
25 changes: 20 additions & 5 deletions tests/unittests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import subprocess
import sys
import textwrap
from unittest.mock import Mock, patch

from azure.functions import Function
from azure.functions.decorators.retry_policy import RetryPolicy
Expand All @@ -25,7 +26,11 @@ def test_function():
self.func = Function(self.test_function, script_file="test.py")
self.function_registry = functions.Registry()

def test_building_fixed_retry_protos(self):
@classmethod
def get_script_dir(cls):
return testutils.UNIT_TESTS_FOLDER / 'load_functions'

def test_loader_building_fixed_retry_protos(self):
trigger = TimerTrigger(schedule="*/1 * * * * *", arg_name="mytimer",
name="mytimer")
self.func.add_trigger(trigger=trigger)
Expand All @@ -38,7 +43,7 @@ def test_building_fixed_retry_protos(self):
self.assertEqual(protos.retry_strategy, 1) # 1 enum for fixed delay
self.assertEqual(protos.delay_interval.seconds, 120)

def test_building_exponential_retry_protos(self):
def test_loader_building_exponential_retry_protos(self):
trigger = TimerTrigger(schedule="*/1 * * * * *", arg_name="mytimer",
name="mytimer")
self.func.add_trigger(trigger=trigger)
Expand All @@ -55,9 +60,19 @@ def test_building_exponential_retry_protos(self):
self.assertEqual(protos.minimum_interval.seconds, 60)
self.assertEqual(protos.maximum_interval.seconds, 120)

@classmethod
def get_script_dir(cls):
return testutils.UNIT_TESTS_FOLDER / 'load_functions'
@patch('azure_functions_worker.logging.logger.warning')
def test_loader_retry_policy_attribute_error(self, mock_logger):
self.func = Mock()
self.func.get_settings_dict.side_effect = AttributeError('DummyError')

result = build_retry_protos(self.func)
self.assertIsNone(result)

# Check if the logged message starts with the expected string
logged_message = mock_logger.call_args[0][
0] # Get the first argument of the logger.warning call
self.assertTrue(logged_message.startswith(
'AttributeError while loading retry policy.'))

def test_loader_simple(self):
r = self.webhost.request('GET', 'simple')
Expand Down

0 comments on commit 72ec585

Please sign in to comment.