fix(declarative): fail fast on unmapped async job status - #1139
fix(declarative): fail fast on unmapped async job status#1139devin-ai-integration[bot] wants to merge 1 commit into
Conversation
Co-Authored-By: bot_apk <apk@cognition.ai>
🤖 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/1787942778-async-unmapped-status-fail-fast#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/1787942778-async-unmapped-status-fail-fastPR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
|
There was a problem hiding this comment.
Pull request overview
This PR improves declarative async-job behavior in the Python CDK by failing fast when the API returns an unmapped or missing job status, preventing unnecessary polling until polling_job_timeout and surfacing a clearer connector/manifest configuration error.
Changes:
- Raise an
AirbyteTracedExceptionwithFailureType.config_errorwhen an async job status is unmapped (or missing), so the orchestrator aborts running jobs immediately. - Add manifest parse-time validation to reject async status mappings that never map any API status to a terminal success (
completedorskipped). - Update and add unit tests covering the new runtime exception behavior and the new parse-time validation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| airbyte_cdk/sources/declarative/requesters/http_job_repository.py | Converts unmapped/missing API status into a config_error traced exception to stop polling immediately. |
| airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py | Adds validation requiring at least one terminal success status mapping (completed/skipped). |
| unit_tests/sources/declarative/requesters/test_http_job_repository.py | Updates tests to assert AirbyteTracedException(config_error) for unknown and missing status cases. |
| unit_tests/sources/declarative/async_job/test_job_orchestrator.py | Adds regression test ensuring config errors from status updates abort running jobs without repeated polling. |
| unit_tests/sources/declarative/parsers/test_model_to_component_factory.py | Adds test ensuring invalid async status mappings fail during component creation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Summary
An async-job stream whose
status_mappingdid not cover a status the API actually returns silently polled untilpolling_job_timeoutexpired instead of failing.AsyncHttpJobRepository._get_validated_job_status()raised a plainValueError, andAsyncJobOrchestrator._is_breaking_exception()only breaks onAirbyteTracedExceptionwithFailureType.config_error, so the unmapped status was recorded as a non-breaking exception, the job stayedRUNNING, and the loop kept polling until the timeout, ending in a generic failure. This was reported from a Connector Builder test read where the async stream took the full timeout before failing.Two changes:
Because the failure type is
config_error, the orchestrator now aborts running jobs and re-raises on the first polling response instead of accumulating a non-breaking exception. This also covers the "absent status" case: when the status extractor yields nothing,api_statusisNone, which is likewise unmapped._create_async_job_status_mapping()now rejects a status map with no terminal success status (nothing mapped tocompletedorskipped), which is a map under which a job can never finish.Note on (2): the issue suggested validating that
runningis non-empty. An emptyrunninglist is legitimate — jobs areRUNNINGfrom creation until a terminal status is reported, and after change (1) an unrecognized non-terminal status fails immediately anyway. A map with nocompleted/skippedentry, by contrast, can never complete, so that is the condition validated here.Declarative-First Evaluation
No custom Python component involved; both changes are in shared CDK code (the async job repository and the declarative parser). No connector manifest changes.
Reproduction
No live reproduction of the originally reported connector was possible (no API credentials available), so this is reproduced at the CDK level instead: the existing
test_given_unknown_status_when_update_jobs_status_then_raise_errormock-HTTP test showed the old plainValueError, and the new orchestrator test reproduces the polling behavior — with the old exception type the orchestrator keeps polling; with aconfig_error-typed exception it raises on the first update and aborts the job.Test Coverage
unit_tests/sources/declarative/requesters/test_http_job_repository.py— unmapped status (invalid_status) and missing status field now assertAirbyteTracedExceptionwithfailure_type == config_error, and that the message names the offending status.unit_tests/sources/declarative/async_job/test_job_orchestrator.py— new regression test: aconfig_errorAirbyteTracedExceptionfromupdate_jobs_statuspropagates out ofcreate_and_get_completed_partitions()on the first iteration (update_jobs_statuscalled exactly once, i.e. no polling until timeout) and running jobs are aborted.unit_tests/sources/declarative/parsers/test_model_to_component_factory.py— anAsyncRetrieverwithcompleted: []and noskippednow fails at component creation.Commands run locally:
Breaking change evaluation
Not a breaking change per the connector breaking-change checklist: no schema, primary key, cursor, spec, stream, data-scope, or state-format change. This is an error-classification change in the CDK — a sync that previously failed after burning
polling_job_timeoutnow fails immediately with a clearer message. The parse-time validation rejects only status maps under which async jobs could never complete. This repo derives its version from semantic-release tooling, so no manual version bump or changelog edit applies.Resolves https://github.com/airbytehq/airbyte-internal-issues/issues/17032:
Requested by Patrick Nilan (@pnilan) on that issue.
Link to Devin session: https://app.devin.ai/sessions/39981653ad284a888e6f44c423481291
Open in Devin Desktop: https://app.devin.ai/desktop/session/39981653ad284a888e6f44c423481291?variant=devin