Skip to content

fix: enforce total timeout in APIBudget._do_acquire instead of per-attempt - #1156

Draft
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1789429618-api-budget-total-timeout
Draft

devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1789429618-api-budget-total-timeout

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Overview

👉 TL;DR: When the rate limiter is asked to wait at most N seconds for a call credit, it could previously wait up to N seconds per retry attempt, so the total wait exceeded the promised limit. It now tracks a single deadline and stops once that total time has elapsed.

Specifically, APIBudget._do_acquire() now computes deadline = time.monotonic() + timeout once and caps each sleep to the remaining time, raising the last CallRateLimitHit when the deadline is exhausted.

Resolves https://github.com/airbytehq/airbyte-internal-issues/issues/17246:

Changes

  • airbyte_cdk/sources/streams/call_rate.py: _do_acquire tracks a monotonic deadline when block=True and timeout is not None; each sleep is min(exc.time_to_wait, remaining); once remaining <= 0 the current CallRateLimitHit is re-raised. Behavior when timeout is None or block=False is unchanged, and the non-negative sleep guard is preserved.
  • unit_tests/sources/streams/test_call_rate.py: new TestAPIBudgetAcquireTimeout class using a fake monotonic clock / patched time.sleep and a stub policy covering: total timeout enforced, timeout=0 raises without sleeping, success before deadline, timeout=None unchanged (success and exhaustion), block=False raises immediately.

Review Spotlight

Reviewers with limited time, please review first:

Reproduction

With a policy that always raises CallRateLimitHit(time_to_wait=60s), maximum_attempts_to_acquire=4, and acquire_call(timeout=1), the old code called time.sleep(1.0) three times (3s total). test_timeout_is_total_budget fails on main with assert [1.0, 1.0, 1.0] == [1.0] and passes with this change.

Risks

  • Behavior change only for callers passing an explicit timeout. The only in-repo production caller (HttpClient via acquire_call) passes no timeout, so this is a latent-bug fix with low blast radius.
  • After sleeping until the deadline, one final try_acquire is attempted before raising, so a caller with timeout=T gets at most ~T seconds of sleep plus one extra acquire attempt.

Follow-ups

Test plan

  • poetry run pytest unit_tests/sources/streams/test_call_rate.py -q — 44 passed
  • poetry run ruff check . / poetry run ruff format --check . on the touched files — clean
  • poetry run mypy --config-file mypy.ini airbyte_cdk/sources/streams/call_rate.py — clean

Requested via /ai-fix on the linked issue (triage: https://github.com/airbytehq/airbyte-internal-issues/issues/17246#issuecomment-5672425513).

Link to Devin session: https://app.devin.ai/sessions/b7b8d969b340427fb9efecfb95ece46f
Open in Devin Desktop: https://app.devin.ai/desktop/session/b7b8d969b340427fb9efecfb95ece46f?variant=devin

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This CDK Version

You can test this version of the CDK using the following:

# Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1789429618-api-budget-total-timeout#egg=airbyte-python-cdk[dev]' --help

# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1789429618-api-budget-total-timeout

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /autofix - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test - Runs connector tests with the updated CDK
  • /prerelease - Triggers a prerelease publish with default arguments
  • /poe build - Regenerate git-committed build artifacts, such as the pydantic models which are generated from the manifest JSON schema in YAML.
  • /poe <command> - Runs any poe command in the CDK environment
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

@github-actions

Copy link
Copy Markdown

PyTest Results (Full)

4 397 tests  +6   4 385 ✅ +6   9m 16s ⏱️ - 4m 45s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit d3607dc. ± Comparison against base commit 96a7c0a.

@github-actions

Copy link
Copy Markdown

PyTest Results (Fast)

4 394 tests  +6   4 382 ✅ +6   9m 12s ⏱️ -26s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit d3607dc. ± Comparison against base commit 96a7c0a.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants