-
Notifications
You must be signed in to change notification settings - Fork 51
feat(low-code): cap the wait WaitUntilTimeFromHeader is willing to return #1123
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
Merged
Daryna Ishchenko (darynaishchenko)
merged 6 commits into
main
from
daryna/cap-wait-until-time-from-header
Aug 20, 2026
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0fa0ace
feat(low-code): cap the wait WaitUntilTimeFromHeader is willing to re…
darynaishchenko e56d75a
fix(low-code): harden and de-duplicate the max_waiting_time_in_second…
darynaishchenko 94a0cc2
fix(low-code): raise a system error when the wait cap cannot be evalu…
darynaishchenko 1b8c981
fix(low-code): let a zero header through the cap, and stop dropping a…
darynaishchenko cd44bc3
fix(low-code): reject a non-finite cap, and align the boundary with t…
darynaishchenko abb15a2
Merge branch 'main' into daryna/cap-wait-until-time-from-header
lazebnyi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
...urces/declarative/requesters/error_handlers/backoff_strategies/max_waiting_time_helper.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| # | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| # | ||
|
|
||
| import math | ||
| from typing import Any, Mapping, Optional, Union | ||
|
|
||
| from airbyte_cdk.models import FailureType | ||
| from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString | ||
| from airbyte_cdk.sources.types import Config | ||
| from airbyte_cdk.utils import AirbyteTracedException | ||
|
|
||
| MAX_WAITING_TIME_FIELD = "max_waiting_time_in_seconds" | ||
|
|
||
|
|
||
| def interpolated_max_waiting_time( | ||
| max_waiting_time_in_seconds: Optional[Union[float, InterpolatedString, str]], | ||
| parameters: Mapping[str, Any], | ||
| ) -> Optional[InterpolatedString]: | ||
| """ | ||
| Cast a `max_waiting_time_in_seconds` field to an InterpolatedString so that a hardcoded number | ||
| and a value interpolated from the config are resolved through the same path. | ||
|
|
||
| :param max_waiting_time_in_seconds: the value as declared on the backoff strategy | ||
| :param parameters: parameters to make available to the interpolation | ||
| :return: the value as an InterpolatedString, or None when no cap is configured | ||
| """ | ||
| if max_waiting_time_in_seconds is None or isinstance( | ||
| max_waiting_time_in_seconds, InterpolatedString | ||
| ): | ||
| return max_waiting_time_in_seconds | ||
| return InterpolatedString.create(str(max_waiting_time_in_seconds), parameters=parameters) | ||
|
|
||
|
|
||
| def evaluate_max_waiting_time( | ||
| max_waiting_time_in_seconds: Optional[InterpolatedString], config: Config | ||
| ) -> Optional[float]: | ||
| """ | ||
| Resolve a `max_waiting_time_in_seconds` field to a number of seconds. | ||
|
|
||
| The `is None` check is deliberate: 0 is a meaningful cap -- "never wait" -- so a truthiness | ||
| check would silently disable it. Only an absent field means "no cap"; a field that is present | ||
| but resolves to nothing raises, rather than quietly leaving the wait unbounded. | ||
|
|
||
| A cap is only read while handling an error the requester is already going to retry, so an | ||
| interpolation that cannot be resolved would otherwise surface as an unhandled jinja | ||
| UndefinedError or ValueError in the middle of a sync that has been running fine. It is raised | ||
| as a system error rather than a config error because the field lives in the manifest: whether | ||
| it is a bad expression or a config key the manifest reads but the spec does not expose, the | ||
| connector is at fault and there is nothing for the user to correct. | ||
|
|
||
| :param max_waiting_time_in_seconds: the interpolated field, or None when no cap is configured | ||
| :param config: the connector config to interpolate against | ||
| :return: the cap in seconds, or None when no cap is configured | ||
| """ | ||
| if max_waiting_time_in_seconds is None: | ||
| return None | ||
| try: | ||
| # A cap that resolves to nothing -- an empty or null config value -- is a failure rather | ||
| # than "no cap": silently dropping the bound restores the unbounded wait the field exists | ||
| # to prevent, and "no cap" is already spelled by leaving the field out of the manifest. | ||
| max_waiting_time = float(max_waiting_time_in_seconds.eval(config)) | ||
| if not math.isfinite(max_waiting_time): | ||
| # NaN would be the one value that disables the cap without saying so: every | ||
| # comparison against it is False, so the wait this field exists to bound would run | ||
| # unbounded again. Infinity is rejected alongside it as the same kind of mistake. | ||
| raise ValueError(f"resolved to {max_waiting_time}, which is not a finite number") | ||
| return max_waiting_time | ||
| except AirbyteTracedException: | ||
| raise | ||
| except Exception as exception: | ||
| raise AirbyteTracedException( | ||
| internal_message=( | ||
| f"Failed to evaluate {MAX_WAITING_TIME_FIELD} " | ||
| f"{max_waiting_time_in_seconds.string!r}: {exception}" | ||
| ), | ||
| message=( | ||
| "The connector could not determine how long it is allowed to wait for a rate " | ||
| "limit to clear. This is a problem with the connector rather than with your " | ||
| "configuration." | ||
| ), | ||
| failure_type=FailureType.system_error, | ||
| ) from exception | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.