feat(low-code): add RateLimitedMultipleTokenAuthenticator component#1066
feat(low-code): add RateLimitedMultipleTokenAuthenticator component#1066Daryna Ishchenko (darynaishchenko) wants to merge 14 commits into
Conversation
… component Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This CDK VersionYou 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/1783347505-rate-limited-multiple-token-authenticator#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/1783347505-rate-limited-multiple-token-authenticatorPR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
|
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
…on wait Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
… already converted Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds a declarative authenticator that rotates multiple tokens using per-request quota pools, refreshes quota state, waits for resets, and throttles proactively. Declarative schemas, factory construction and caching, public exports, enum serialization, and comprehensive runtime and integration tests are updated. ChangesRate-limited multi-token authentication
Advanced authentication spec serialization
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Request as PreparedRequest
participant Auth as RateLimitedMultipleTokenAuthenticator
participant Quota as quota-status endpoint
Request->>Auth: submit request for authentication
Auth->>Quota: fetch quota state for tokens
Quota-->>Auth: return remaining and reset values
Auth->>Auth: match quota pool and reserve token
Auth-->>Request: attach authorization header
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
airbyte_cdk/sources/declarative/spec/spec.py (1)
58-69: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy liftCould we normalize a serialized copy instead of mutating the typed model?
generate_spec()assigns.valuestrings back into Enum-backed fields, so after the first callself.advanced_authno longer conforms to its declared model contract. This fixes repeated serialization, but can break callers that reuseadvanced_authand expectAuthFlowType/ScopesJoinStrategyinstances. Could you build the output dictionary first and normalize that copy instead, wdyt?🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@airbyte_cdk/sources/declarative/spec/spec.py` around lines 58 - 69, The generate_spec() serialization flow currently mutates Enum-backed fields on self.advanced_auth and its nested oauth configuration. Build or obtain a serialized output copy first, then normalize auth_flow_type and scopes_join_strategy on that copy only, preserving the typed AuthFlow and OAuth connector input models for repeated callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@airbyte_cdk/sources/declarative/auth/rate_limited_multiple_token.py`:
- Around line 165-205: The _acquire_call exhaustion path currently applies
_max_wait_time to each sleep rather than the full retry loop. Track a single
exhaustion deadline across repeated reset/refresh iterations, bound each wait by
the remaining time, and raise the existing transient AirbyteTracedException when
that cumulative budget is exhausted; add a regression test covering repeated
zero-quota refreshes.
In `@airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py`:
- Around line 725-726: The shared authenticator registry must be reused by
nested ModelToComponentFactory instances so parent and child streams share
rate-limit counters. Update the parent-stream factory creation paths around
ModelToComponentFactory and the related factory construction at 4514-4526 to
accept and propagate the parent’s _rate_limited_authenticators mapping, rather
than initializing a fresh registry; preserve the existing local initialization
only for root factories.
In `@unit_tests/sources/declarative/auth/test_rate_limited_multiple_token.py`:
- Around line 186-211: Update
test_thread_safety_header_token_matches_decremented_token to capture exceptions
raised by each worker in make_call, using the existing thread coordination or an
equivalent mechanism, and assert that the collected exception list is empty
after all threads join. Keep the signed token collection and per-token
remaining-quota assertions unchanged.
---
Nitpick comments:
In `@airbyte_cdk/sources/declarative/spec/spec.py`:
- Around line 58-69: The generate_spec() serialization flow currently mutates
Enum-backed fields on self.advanced_auth and its nested oauth configuration.
Build or obtain a serialized output copy first, then normalize auth_flow_type
and scopes_join_strategy on that copy only, preserving the typed AuthFlow and
OAuth connector input models for repeated callers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 53a02d6d-190c-4424-9f9f-d4b367840869
📒 Files selected for processing (7)
airbyte_cdk/sources/declarative/auth/__init__.pyairbyte_cdk/sources/declarative/auth/rate_limited_multiple_token.pyairbyte_cdk/sources/declarative/declarative_component_schema.yamlairbyte_cdk/sources/declarative/models/declarative_component_schema.pyairbyte_cdk/sources/declarative/parsers/model_to_component_factory.pyairbyte_cdk/sources/declarative/spec/spec.pyunit_tests/sources/declarative/auth/test_rate_limited_multiple_token.py
…es; capture worker exceptions in thread-safety test Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Anatolii Yatsuk (tolik0)
left a comment
There was a problem hiding this comment.
Deep review with local reproductions (ran the PR's tests, drove it end-to-end through ConcurrentDeclarativeSource manifests, replicated the model codegen, and compared behavior against source-github's MultipleTokenAuthenticatorWithRateLimiter). The core machinery works and thread safety is done correctly, but two must-fix items remain — see inline comments:
- High: the shared-instance cache key is poisoned by
$parameterspropagation, so streams get separate counter sets in realistic manifests (reproduced on this head). - Medium: the checked-in generated models file is out of sync with the schema (hand-edited, not regenerated).
Also a medium on max_wait_time not being a cumulative bound (reproduced infinite reseed loop), plus several low-severity robustness notes. The substream-factory registry sharing added in d92aaac was verified working with a parent/child manifest.
…enticator - Build shared-instance cache key from resolved constructor args so propagated $parameters cannot break instance sharing - Enforce cumulative max_wait_time across an exhaustion episode to prevent infinite reseed loops - Regenerate declarative_component_schema.py via codegen - Filter empty tokens in list form; validate max_wait_time is a fixed-length duration - Warn once on unmatched quota fallback; raise config_error for empty quotas - Share authenticator registry via constructor injection - Make Spec.generate_spec idempotent (normalize serialized dict, never mutate the model) Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
…tible style Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Co-Authored-By: Daryna Ishchenko <darina.ishchenko17@gmail.com>
Summary
Adds a new declarative authenticator,
RateLimitedMultipleTokenAuthenticator, that generalizes source-github'sMultipleTokenAuthenticatorWithRateLimiterso it can be reused by any connector during declarative migrations (context: https://github.com/airbytehq/airbyte-internal-issues/issues/16512).Behavior (per outgoing request, via
AuthBase.__call__):quotas) viaHttpRequestRegexMatchers; a pool with no matchers is the default (generalizes GitHub's hardcoded"graphql" in pathREST-vs-GraphQL split).quota_status_source(e.g. GitHubGET /rate_limit) usingremaining_path/reset_path/limit_pathdpath extraction. Seeding is lazy (first request) and repeated after an exhaustion wait.MIN_EXHAUSTION_WAIT= 5s so stale reset timestamps can't busy-loop the quota endpoint, bounded bymax_wait_time, else raisestransient_error).max(budget_min_reserve, budget_reserve_fraction * limit), delays ofseconds_to_reset / total_remaining(capped at 10s) are injected for graceful degradation instead of a hard wall.Thread safety (new vs. the source-github implementation, required for the concurrent CDK):
RLock;_acquire_callreturns the token chosen under the lock and the request header is built from that value, so a request is always signed with the token whose counter was decremented (no TOCTOU with concurrent rotation). All sleeps occur outside the lock._refresh_lockso only one thread refreshes counters after an exhaustion wait.ModelToComponentFactory.create_rate_limited_multiple_token_authenticatorcaches instances keyed on the model definition, so all streams share one counter set (same idea as the sharedapi_budget).Example manifest usage (source-github):
Changes:
declarative_component_schema.yaml: newRateLimitedMultipleTokenAuthenticator,QuotaStatusSource,TokenQuotadefinitions; added toHttpRequester.authenticatorandSelectiveAuthenticator.authenticatorsunions (models regenerated; new classes applied on top of the checked-in file to avoid unrelated codegen churn).airbyte_cdk/sources/declarative/auth/rate_limited_multiple_token.py: runtime implementation.model_to_component_factory.py:create_rate_limited_multiple_token_authenticatorwith token-string splitting, interpolation, and shared-instance caching.Requested by Daryna Ishchenko (darynaishchenko).
Link to Devin session: https://app.devin.ai/sessions/3ced8f6a11d44ed4abc517221294f767
Requested by: Daryna Ishchenko (@darynaishchenko)
Summary by CodeRabbit