-
Notifications
You must be signed in to change notification settings - Fork 4.6k
[low-code]: Evaluate backoff strategies at runtime #18053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
da45217
6aa1b52
b5efdfa
d654001
7b61f1d
3a0efed
72f749b
0093b08
4aa4b25
7598e01
9e90ff5
2e7ce39
f20d1db
de519ca
0a0db98
0efe44b
dcc4da3
4de6ea3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -229,14 +229,17 @@ def _create_subcomponent(self, key, definition, kwargs, config, parent_class, in | |
options = kwargs.get(OPTIONS_STR, {}) | ||
try: | ||
# enums can't accept options | ||
if issubclass(expected_type, enum.Enum): | ||
if issubclass(expected_type, enum.Enum) or self.isBuiltinTypes(definition): | ||
return expected_type(definition) | ||
else: | ||
return expected_type(definition, options=options) | ||
except Exception as e: | ||
raise Exception(f"failed to instantiate type {expected_type}. {e}") | ||
return definition | ||
|
||
def isBuiltinTypes(self, obj): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. snake case instead? |
||
return isinstance(obj, (int, float, bool)) | ||
|
||
@staticmethod | ||
def is_object_definition_with_class_name(definition): | ||
return isinstance(definition, dict) and "class_name" in definition | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,13 @@ | |
# Copyright (c) 2022 Airbyte, Inc., all rights reserved. | ||
# | ||
|
||
from dataclasses import dataclass | ||
from typing import Optional | ||
from dataclasses import InitVar, dataclass | ||
from typing import Any, Mapping, Optional, Union | ||
|
||
import requests | ||
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString | ||
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy | ||
from airbyte_cdk.sources.declarative.types import Config | ||
from dataclasses_jsonschema import JsonSchemaMixin | ||
|
||
|
||
|
@@ -19,7 +21,14 @@ class ConstantBackoffStrategy(BackoffStrategy, JsonSchemaMixin): | |
backoff_time_in_seconds (float): time to backoff before retrying a retryable request. | ||
""" | ||
|
||
backoff_time_in_seconds: float | ||
backoff_time_in_seconds: Union[float, InterpolatedString, str] | ||
options: InitVar[Mapping[str, Any]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add options and config parameters |
||
config: Config | ||
|
||
def __post_init__(self, options: Mapping[str, Any]): | ||
if not isinstance(self.backoff_time_in_seconds, InterpolatedString): | ||
self.backoff_time_in_seconds = str(self.backoff_time_in_seconds) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. convert to string if needed |
||
self.backoff_time_in_seconds = InterpolatedString.create(self.backoff_time_in_seconds, options=options) | ||
|
||
def backoff(self, response: requests.Response, attempt_count: int) -> Optional[float]: | ||
return self.backoff_time_in_seconds | ||
return self.backoff_time_in_seconds.eval(self.config) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eval at runtime |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,17 +8,23 @@ | |
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.constant_backoff_strategy import ConstantBackoffStrategy | ||
|
||
BACKOFF_TIME = 10 | ||
OPTIONS_BACKOFF_TIME = 20 | ||
CONFIG_BACKOFF_TIME = 30 | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"test_name, attempt_count, expected_backoff_time", | ||
"test_name, attempt_count, backofftime, expected_backoff_time", | ||
[ | ||
("test_exponential_backoff", 1, BACKOFF_TIME), | ||
("test_exponential_backoff", 2, BACKOFF_TIME), | ||
("test_constant_backoff_first_attempt", 1, BACKOFF_TIME, BACKOFF_TIME), | ||
("test_constant_backoff_second_attempt", 2, BACKOFF_TIME, BACKOFF_TIME), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also add a test for a float? Right now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brianjlai are you referring to the backoff time or the attempt count? I added tests for both.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i just meant for backoff time, we were using the constants for |
||
("test_constant_backoff_from_options", 1, "{{ options['backoff'] }}", OPTIONS_BACKOFF_TIME), | ||
("test_constant_backoff_from_config", 1, "{{ config['backoff'] }}", CONFIG_BACKOFF_TIME), | ||
], | ||
) | ||
def test_exponential_backoff(test_name, attempt_count, expected_backoff_time): | ||
def test_constant_backoff(test_name, attempt_count, backofftime, expected_backoff_time): | ||
response_mock = MagicMock() | ||
backoff_strategy = ConstantBackoffStrategy(backoff_time_in_seconds=BACKOFF_TIME) | ||
backoff_strategy = ConstantBackoffStrategy( | ||
options={"backoff": OPTIONS_BACKOFF_TIME}, backoff_time_in_seconds=backofftime, config={"backoff": CONFIG_BACKOFF_TIME} | ||
) | ||
backoff = backoff_strategy.backoff(response_mock, attempt_count) | ||
assert backoff == expected_backoff_time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can't pass the options parameter if the expected_type is an int, float, or bool